sync.WaitGroup 是轻量不可复制的同步原语,Add 必须在 goroutine 启动前调用,Done 应 defer 调用,可重用但禁止 Add 与 Wait 并发,零值安全但严禁复制。
不是“教程工具”,它是一个轻量、不可复制、需谨慎调用的同步原语——用错一次就 panic,写对了才真正省事。
WaitGroup.Add 必须在 goroutine 启动前调用
这是最常踩的坑:把
放在
语句之后,或塞进 goroutine 里,会导致
永远不返回,或 panic “negative WaitGroup counter”。
的作用是预登记“待等待任务数”,必须在
启动前完成
闭包中若用循环变量(如
),要传参避免所有 goroutine 共享同一个
值
如果任务数动态不确定(比如从 channel 拉取),得先 collect 再
,不能边拉边
Done 要确保执行,推荐 defer wg.Done()
是计数器减 1,漏调 = 计数器卡住 =
死锁。用
是最稳妥的方式,但要注意:
必须在 goroutine 内部调用,不能由主 goroutine 代劳
如果函数有多个 return 路径(比如 error early return),
能覆盖全部出口
不要在
后再操作共享资源(如往结果 channel 写入),除非你已加锁或用其他同步机制保护
WaitGroup 可重用,但不能并发 Add + Wait 混用
很多人以为
是一次性对象,其实只要
返回后计数器为 0,它就回到了零值状态,可以再次
。
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
重用没问题:
返回后,直接
启新一批任务是安全的
但禁止在
还没返回时,从另一个 goroutine 调用
—— 这会触发 panic “WaitGroup misuse”
多个 goroutine 同时调用
是允许的,计数器归零时它们会一起被唤醒
别把 WaitGroup 当 channel 用,错误处理要另配机制
只回答“是否全做完”,不回答“做得对不对”。常见错误是只等不收错:
立即学习
“
go语言免费学习笔记(深入)
”;
想收集错误?得配
或切片 + 互斥锁,
本身不传值
想收返回结果?同样要额外 channel 或指针参数,
不持有任何业务数据
别试图用
控制超时——它没有 context 支持,超时得靠
+
或
真正容易被忽略的点是:WaitGroup 的零值是安全的,但它的内存布局含原子字段,一旦被复制(比如作为 struct 字段值拷贝、传参没取地址),就会破坏内部状态。所以永远用
传参,声明时用
,传给函数时传
。
sync.WaitGroupwg.Add(1)goWait()Addgofor i := range urlsiAdd(len(tasks))AddDone()Wait()deferdeferDone()WaitGroup{}Wait()Add()wg.Wait()wg.Add(5)Wait()Add()Wait()WaitGroupchan errorWaitGroupWaitGroupWaitGroupselecttime.Aftercontext.WithTimeout*sync.WaitGroupvar wg sync.WaitGroup&wg