简介
-
内容介绍
WaitGroup 对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait() 用来控制计数器的数量。
Add(n) 把计数器设置为n
Done() 每次把计数器-1
Wait() 会阻塞代码的运行,直到计数器地值减为0。
适用场景
-
场景说明
主线程等待所有线程执行结束再继续执行
使用样例
-
反例
主线程为了等待goroutine都运行完毕,不得不在程序的末尾使用time.Sleep() 来睡眠一段时间,等待其他线程充分运行。对于简单的代码,100个for循环可以在1秒之内运行完毕,time.Sleep() 也可以达到想要的效果。
import ( "fmt" "time" ) func main(){ for i := 0; i < 100 ; i++{ go fmt.Println(i) } time.Sleep(time.Second) }
-
正例
这里首先把 wg 计数设置为100, 每个for循环运行完毕都把计数器减一,主函数中使用 Wait() 一直阻塞,直到wg为零——也就是所有的100个for循环都运行完毕。相对于使用主线程睡眠来说 WaitGroup 更合理。
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() }
注意事项
-
WaitGroup对象不是一个引用类型
WaitGroup对象不是一个引用类型,在通过函数传值的时候需要使用地址
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() }
参考链接
-
Go 并发
https://www.runoob.com/go/go-concurrent.html
-
Golang sync.WaitGroup的用法
https://studygolang.com/articles/12972