go WaitGroup的使用请参考笔者的另外一篇博客
这里重点讲一下WaitGroup的注意点,以免被坑
示例代码如下:
package main
import (
"log"
"sync"
)
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 5; i++ {
wg.Add(1)
go func(wg sync.WaitGroup, i int) {
log.Printf("i:%d", i)
wg.Done()
}(wg, i)
}
wg.Wait()
log.Println("exit")
}
代码很简单,主协程中新建5个子协程,每个子协程中打印数字后即结束,调用Done(),按照我们的代码执行应该是子协程打印参数后,主协程Wait()结束,打印exit,最终结束
但实际上执行结果却是下面:
竟然出错了!!!!!
是因为子协程函数的参数sync.WaitGroup,我们传入的是对象,是wg的新构造的临时对象,而非指针,所以Done()是在那个新的对象中执行的,而非我们的全局变量wg,所以全局变量wg没有子线程Done(),一直等待,造成了死锁
其实代码写完后,智能的编译器已经给出了提示,请看下图
请看弹框的内容,即sync.WaitGroup是不可拷贝构造的
所以我们把参数由对象改为指针时,即可修复
代码及执行效果如下:
package main
import (
"log"
"sync"
)
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 5; i++ {
wg.Add(1)
go func(wg *sync.WaitGroup, i int) {
log.Printf("i:%d", i)
wg.Done()
}(&wg, i)
}
wg.Wait()
log.Println("exit")
}