Go sync包的WaitGroup【同步等待组】详解

sync全称是synchronization,意思是同步。
WaitGroup同步等待组是有一组goroutine要等待执行,而当前的goroutine需要等待这一组goroutine都执行完才能执行。
下面是WaitGroup的定义:

type WaitGroup struct { // }

每个WaitGroup中都有一个计数器counter记录要等待执行gorouting的数量,可以通过Add这个方法来设置同步等待组中等待goroutine的个数。每个goroutine都会执行,执行完之后都会调用done方法表示把计数器的值-1,与此同时,使用wait方法阻塞,直到所goroutine都执行完毕。
func (wg *WaitGroup) Add(delta int)
  • 如果计数器的值为0,那么等待过程中被阻塞的goroutine都会被释放
  • 如果计数器得知为负,那么就会引发panic
那么具体什么情况下用,怎么使用呢?
下面举个例子:
package mainimport "fmt"func main() { //waitGroup go fun1() go fun2() }func fun1() { for i := 1; i < 10; i++ { fmt.Println("print A in fun1", i) } }func fun2() { for i := 0; i < 10; i++ { fmt.Println("\t fun2 print: ", i) } }

这样最后什么都没有打印,因为主goroutine在fun1 fun2这两个goroutine执行之前结束了。这时候就可以用WaitGroup了。
package mainimport ( "fmt" "sync" )//创建同步等待组 var wg sync.WaitGroupfunc main() { //waitGroup wg.Add(2) //设置计数器为2(goroutine的个数) go fun1() go fun2() fmt.Println("main 进入阻塞状态, 需要等待wg的goroutine结束") wg.Wait() //表示main goroutine进入阻塞 fmt.Println("计数器归零 停止阻塞") }func fun1() { defer wg.Done() //计数器-1 for i := 1; i < 10; i++ { fmt.Println("print A in fun1", i) } }func fun2() { defer wg.Done() //计数器-1 for i := 0; i < 10; i++ { fmt.Println("\t fun2 print: ", i) } }

【Go sync包的WaitGroup【同步等待组】详解】结果如下:
main 进入阻塞状态, 需要等待wg的goroutine结束 print A in fun1 1 print A in fun1 2 fun2 print:0 fun2 print:1 fun2 print:2 fun2 print:3 fun2 print:4 print A in fun1 3 print A in fun1 4 print A in fun1 5 print A in fun1 6 print A in fun1 7 print A in fun1 8 print A in fun1 9 fun2 print:5 fun2 print:6 fun2 print:7 fun2 print:8 fun2 print:9 计数器归零 停止阻塞

结果第一行,说明两个goroutine已经都启动了,然后交替使用CPU的时间片。
另外 如果函数执行完毕的时候,计数器的值仍然大于0,会引起deadlock。
另外 Go语言并不推荐上述写法,更加推荐使用chanel。
资料参考:bilibili

    推荐阅读