sync.waitGroup 原理分析
前言#
sync
的常用包好像都快讲完了, 最近几天进度很快啊, 希望能多多保持.
sync.WaitGroup
是为了解决任务编排而出现的, 主要就是解决并发-等待问题, 因此在真正编写过程中也很常用, 本篇大致讲解其内部实现的方式
Demo#
简单介绍一下用法
func main() {
wg := sync.WaitGroup{}
wg.Add(1) // wg计数+1
go func() {
defer wg.Done() // wg计数-1
time.Sleep(3 * time.Second)
}()
wg.Wait() // 等待 wg 结束(wg计数为0)
}
对应sync.WaitGroup
来讲, 只有三种方法:
Add(delta int)
: 为计数器添加一定的数字Done()
: 为计数器数字减去1Wait()
: 夯住等待计数器数字变成0
结构#
和往常一样, 先从结构开始看起
type WaitGroup struct {
// 避免复制使用的一个技巧,可以告诉vet工具违反了复制使用的规则
noCopy noCopy
// 64bit(8bytes)的值分成两段,高32bit是计数值,低32bit是waiter的计数
// 另外32bit是用作信号量的
// 因为64bit值的原子操作需要64bit对齐,但是32bit编译器不支持,所以数组中的元素在不同的架构中不一样,具体处理看下面的方法
// 总之,会找到对齐的那64bit作为state,其余的32bit做信号量
state1 [3]uint32
}
noCopy
: 这个是一个使用技巧, 如果一个结构体中有此字段, vet 工具会在编译时检查避免被 copy 使用state1
: 从定义可以看出, 其长度为3, 每个32bit, 里面包含了waitGroup
的计数值和信号量和 waiter 计数
state1 结构
state[0] // 调用 wait 等待的 goroutine 数量
state[1] // 计数
state[2] // 信号量
Add#
Add
主要是对state1
字段中的计数值部分进行操作, 步骤如下:
- 将参数
delta
左移32位 - 将值加到计数值上(
state1[1]
), 这个值是可负可正
Done#
Done
实际上就是调用Add(-1)
而检测到-1
之后的计数值为0时, 通过信号量唤醒正在wait
的阻塞协程
Wait#
调用wait
时, 会将waiter
+1, 然后将自身加入到等待队列中并阻塞, 等待Done
时的唤醒
作者:chnmig
出处:https://www.cnblogs.com/chnmig/p/16744182.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」