主要观点:作者在面试中被同事问到关于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) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。