0x01 介绍

经常会看到以下了代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"fmt"
"time"
) func main(){
for i := 0; i < 100 ; i++{
go fmt.Println(i)
}
time.Sleep(time.Second)
}

主线程为了等待goroutine都运行完毕,不得不在程序的末尾使用time.Sleep() 来睡眠一段时间,等待其他线程充分运行。对于简单的代码,100个for循环可以在1秒之内运行完毕,time.Sleep() 也可以达到想要的效果。

但是对于实际生活的大多数场景来说,1秒是不够的,并且大部分时候我们都无法预知for循环内代码运行时间的长短。这时候就不能使用time.Sleep() 来完成等待操作了。

可以考虑使用管道来完成上述操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
c := make(chan bool, 100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
c <- true
}(i)
} for i := 0; i < 100; i++ {
<-c
}
}

首先可以肯定的是使用管道是能达到我们的目的的,而且不但能达到目的,还能十分完美的达到目的。

但是管道在这里显得有些大材小用,因为它被设计出来不仅仅只是在这里用作简单的同步处理,在这里使用管道实际上是不合适的。而且假设我们有一万、十万甚至更多的for循环,也要申请同样数量大小的管道出来,对内存也是不小的开销。

对于这种情况,go语言中有一个其他的工具sync.WaitGroup 能更加方便的帮助我们达到这个目的。

WaitGroup 对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait() 用来控制计数器的数量。Add(n) 把计数器设置为n ,Done() 每次把计数器-1 ,wait() 会阻塞代码的运行,直到计数器地值减为0。

使用WaitGroup 将上述代码可以修改为:

1
2
3
4
5
6
7
8
9
10
11
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
wg.Done()
}(i)
}
wg.Wait()
}

这里首先把wg 计数设置为100, 每个for循环运行完毕都把计数器减一,主函数中使用Wait() 一直阻塞,直到wg为零——也就是所有的100个for循环都运行完毕。相对于使用管道来说,WaitGroup 轻巧了许多。

0x02 注意事项

1. 计数器不能为负值

我们不能使用Add() 给wg 设置一个负值,否则代码将会报错:

1
2
3
4
5
6
7
panic: sync: negative WaitGroup counter

goroutine 1 [running]:
sync.(*WaitGroup).Add(0xc042008230, 0xffffffffffffff9c)
D:/Go/src/sync/waitgroup.go:75 +0x1d0
main.main()
D:/code/go/src/test-src/2-Package/sync/waitgroup/main.go:10 +0x54

同样使用Done() 也要特别注意不要把计数器设置成负数了。

2. WaitGroup对象不是一个引用类型

WaitGroup对象不是一个引用类型,在通过函数传值的时候需要使用地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go f(i, &wg)
}
wg.Wait()
} // 一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup) {
fmt.Println(i)
wg.Done()
}

Golang sync.WaitGroup的用法的更多相关文章

  1. Golang Sync.WaitGroup 使用及原理

    Golang Sync.WaitGroup 使用及原理 使用 func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.A ...

  2. golang sync.WaitGroup

    //阻塞,直到WaitGroup中的所以过程完成. import ( "fmt" "sync" ) func wgProcess(wg *sync.WaitGr ...

  3. golang sync.WaitGroup bug

    注意,这个结构体,要是想在函数之间传来传去的话,必须要使用指针....... 这个结构体里没有 指针,这个类型可以说没有“引用特性”. 被坑了一晚上.特此记录.

  4. golang-----golang sync.WaitGroup解决goroutine同步

    go提供了sync包和channel来解决协程同步和通讯.新手对channel通道操作起来更容易产生死锁,如果时缓冲的channel还要考虑channel放入和取出数据的速率问题. 从字面就可以理解, ...

  5. golang 的 sync.WaitGroup

    WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成. 官方对它的说明如下: A WaitGroup waits for ...

  6. Golang的sync.WaitGroup 实现逻辑和源码解析

    在Golang中,WaitGroup主要用来做go Routine的等待,当启动多个go程序,通过waitgroup可以等待所有go程序结束后再执行后面的代码逻辑,比如: func Main() { ...

  7. Golang之waitgroup用法

    我敲下一堆代码,终于长出了果实,今天是个伟大日子 package main import ( "fmt" "sync" "time" ) / ...

  8. golang的sync.WaitGroup使用示例

    下面一段代码 len(m) 不一定会打印为 10,为什么?.如果想要 len(m) 打印为 10,应该怎么修改代码? func main() { const N = 10 m := make(map[ ...

  9. golang sync.noCopy 类型 —— 初探 copylocks 与 empty struct

    问题引入 学习golang(v1.16)的 WaitGroup 代码时,看到了一处奇怪的用法,见下方类型定义: type WaitGroup struct { noCopy noCopy ... } ...

随机推荐

  1. hi 北京

    一 . 感慨 借着参加北京物联网展会的这次机会,提前找老师批了大概两周的假期.当然也借着这次机会,尝试了第一次坐飞机.第一次来北京.心里也有点小激动,在路上甚至会想,我是不是要重新规划一下我的人生了呢 ...

  2. 你不知道的JavaScript LHS 和 RHS 查找

    今天在学习JavaScript的相关知识时接触到了 LHS(Left Hand Side)和 RHS(Right Hand Side)两种对变量查找的方法,之所以JavaScript要查找变量,那就先 ...

  3. Vue -- element-ui FileSaver.js 导出

    html <el-button type="danger" @click="exportRs">导出Excel报表</el-button> ...

  4. 指定js文件不使用 ESLint 语法检查

    整个文件范围内禁止规则出现警告 将/* eslint-disable */放置于文件最顶部 /* eslint-disable */ alert('foo'); 在文件中临时禁止规则出现警告 将需要忽 ...

  5. FFmpeg处理音视频流程学习笔记

    原文作者:一叶知秋0830 链接:https://www.jianshu.com/p/1b715966af50 FFmpeg处理音视频完整流程包括5个阶段(输入文件—>编码数据包—>解码后 ...

  6. Appium自动化测试教程-自学网-monkey参数

    monkey 参数 参数分类 · 常规类参数 · 事件类参数 · 约束类参数 · 调试类参数 常规类参数 常规类参数包括帮助参数和日志信息参数.帮助参数用于输出Monkey命令使用指导:日志信息参数将 ...

  7. Linux 安装python3.7

    首先需要安装依赖 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-dev ...

  8. poi操作excel之: 将NUMERIC转换成TEXT

    一.NUMERIC TO TEXT(生成excel)代码生成一个excel文件: public static void generateExcel() throws Exception { XSSFW ...

  9. locale与C字符编码

    ref: https://www.cnblogs.com/gatsby123/p/11150472.html Unicode 字符集 代码点 与编码表中的某个字符对应的代码值.在Unicode标准中, ...

  10. 系统信息的管理函数API

    1.Windows系统信息 1.1获取系统版本:   BOOL WINAPI GetVersionEx( __in_out LPOSVERSIONINFO lpVersionInfo ); lpVer ...