Golang WaitGroup 原理深度剖析
sync.WaitGroup 是 Golang 中常用的并发措施,我们可以用它来等待一批 Goroutine 结束。
WaitGroup 的源码也非常简短,抛去注释外也就 100 行左右的代码。但即使是这 100 行代码,里面也有着关乎内存优化、并发安全考虑等各种性能优化手段。
本文将基于 go-1.13 的源码 进行分析,将会涉及以下知识点:
- WaitGroup 的实现逻辑
- WaitGroup 的底层内存结构及性能优化
- WaitGroup 的内部如何实现无锁操作
WaitGroup 的使用
在正式分析源码之前,我们先看下 WaitGroup 的基本用法:
1 | func main() { |
从上述代码可以看出,WaitGroup 的用法非常简单:使用 Add 添加需要等待的个数,使用 Done 来通知 WaitGroup 任务已完成,使用 Wait 来等待所有 goroutine 结束。
WaitGroup 的实现逻辑
我们首先看下 WaitGroup 的组成结构,代码如下:
1 | type WaitGroup struct { |
其中 noCopy 是 golang 源码中检测禁止拷贝的技术。如果程序中有 WaitGroup 的赋值行为,使用 go vet 检查程序时,就会发现有报错。但需要注意的是,noCopy 不会影响程序正常的编译和运行。
state1 [3]uint32 字段中包含了 WaitGroup 的所有状态数据。该字段的整个设计其实非常复杂,为了便于快速理解 WaitGroup 的主流程,我们将在后面部分单独剖析 state1。
为了便于理解 WaitGroup 的整个实现过程,我们暂时先不考虑内存对齐和并发安全等方面因素。那么 WaitGroup 可以近似的看做以下代码:
1 | type WaitGroup struct { |
其中:
counter代表目前尚未完成的个数。WaitGroup.Add(n)将会导致counter +=...
剩余内容已隐藏