Go sync.WaitGroup源码阅读

WaitGroup并发控制

sync.WaitGroup内部维护着一个计数器,计数器的值可以增加和减少。

例如当我们启动了N 个并发任务时,就通过Add()将计数器值增加N

每个任务完成通过调用Done()方法将计数器减1

通过调用Wait()来等待并发任务执行完,当计数器值为0时,表示所有并发任务已经完成。

const N = 10

var wg = &sync.WaitGroup{}

func main() {

    for i := 0; i < N; i++ {
        //wg.Add(1) 正确写法
        go func(i int) {
            wg.Add(1)
            println(i)
            defer wg.Done()
        }(i)
    }
    wg.Wait()

}

结果

结果不唯一,代码存在风险, 所有go未必都能执行到

这是使用WaitGroup经常犯下的错误!请各位同学多次运行就会发现输出都会不同甚至又出现报错的问题。 这是因为go执行太快了,导致wg.Add(1)还没有执行main函数就执行完毕了。

底层原理

type WaitGroup struct {
   noCopy noCopy

   state1 [3]uint32  // uint32数组一共12个字节,前8个即uint64记录 高8位记录需要等待的数量 低8位正在等待                       的数量  ,后4个字节存储信号量,用于唤醒
}

1.核心原理就是通过之前说的64位的uint64来进行计数,采用高位记录需要Done的数量,低位记录Wait的数量,然后排队休眠等待唤醒

2.如果发现当前count>0则 Wait的goroutine会进行排队

3.任务完成后的goroutine则进行Done操作,直到count==0,则完成,就唤醒所有因为wait操作睡眠的goroutine

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容