主要观点:作者在面试中被同事问到关于sync.WaitGroup
的使用问题,意识到自己未完全理解其内部工作原理,遂在周末进行研究并撰写此文。
关键信息:
- 从
pkg.go.dev
的文档开始了解WaitGroup
,其用于等待一组协程完成,Add
设置要等待的协程数量,Done
表示协程完成,Wait
用于阻塞直到所有协程完成。 sync.WaitGroup
的结构体定义包含noCopy
、state
和sema
,noCopy
用于防止值被复制,state
存储WaitGroup
的状态,sema
是信号量值。Add
函数用于添加计数器值,Done
函数实际上是Add(-1)
,Wait
函数尝试获取信号量值,通过for
循环和CompareAndSwap
操作来实现。
重要细节:noCopy
通过在接口上实现Lock
和Unlock
函数来防止值被复制,go vet
会在看到这种情况时发出警告。state
的高 32 位存储计数器,低 32 位存储等待者数量。- 信号量可以看作一个整数,有
acquire
(获取)和release
(释放)操作,acquire
检查信号量值是否大于 0 并递减,release
增加信号量值表示资源可用。 runtime_Semrelease
和runtime_Semacquire
是在go
代码库中实际实现信号量操作的函数,涉及到协程的暂停和恢复。WaitGroup
的内部实现通过原子操作和循环来确保正确的同步和等待。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。