go waitgroup 的坑

参考解析

题目来源:欢聚集团

答案1:

1、waitGroup对象做值传递

  1. 如:
  1. func main(){
  2. var swg sync.WaitGroup
  3. for i:=0;i<3;i++{
  4. swg.Add(1)
  5. go func(wg sync.WaitGroup,mark int){
  6. defer wg.Done()
  7. fmt.Printf("%d goroutine finish
  8. ",mark)
  9. }(swg,i)
  10. }
  11. swg.Wait()
  12. }
  13. //运行结果:
  14. // 0 goroutine finish
  15. // 1 goroutine finish
  16. // 2 goroutine finish
  17. // fatal error: all goroutines are asleep - deadlock!

​ 子协程中传入的waitGroup对象的一份新值拷贝,在main主协程的waitGroup对象并没有被调用Done()方法,导致标志位无法被释放,最后发生死锁。

​ 所以,将waitGroup对象做参数传递时,使用其引用拷贝传入。

2、仅在子协程goroutine中进行add操作

​ 如:

  1. func main() {
  2. wg := sync.WaitGroup{}
  3. for i := 0; i < 5; i++ {
  4. go func(wg *sync.WaitGroup, i int) {
  5. wg.Add(1)
  6. log.Printf("i:%d", i)
  7. wg.Done()
  8. }(&wg, i)
  9. }
  10. wg.Wait()
  11. log.Println("exit")
  12. }
  13. //运行结果(可能出现):
  14. // 2022/05/09 09:38:36 exit

​ 因为子协程跟main主协程同步进行,可能子协程中还没来得及add(1),mian主线程就已经执行结束了。

​ 所以,尽量不要仅在子协程中进行add操作。