sync: WaitGroup在Wait返回前被复用引发Panic问题咨询
问题:sync.WaitGroup 触发 panic: sync: WaitGroup is reused before previous Wait has returned
生产环境中大量goroutine并发运行以下代码片段时,一段时间后触发panic:sync: WaitGroup is reused before previous Wait has returned。将WaitGroup设为全局变量可复现该问题,但当前提供的代码片段无法直接复现。
关键代码片段
func check() { .......check condition...... //skipEnsure and skipNative will not both false here var wg sync.WaitGroup if !skipEnsure { wg.Add(1) go func(wg *sync.WaitGroup) { defer wg.Done() dosomething1() }(&wg) } if !skipNative { wg.Add(1) go func(wg *sync.WaitGroup) { defer wg.Done() dosomething2() }(&wg) } wg.Wait() //panic here } func worker() { ...... go check() } func main() { for i:=0;i<32;i++ { go worker() } ch := make(chan any, 0) <-ch }
问题原因
- 你提供的代码中
WaitGroup是check函数的局部变量,理论上每次调用check都会创建新实例,不会出现复用冲突。但生产环境触发panic,说明实际代码里的WaitGroup并非每次调用都新建——大概率是被定义在check外部(比如全局变量、闭包捕获的外部变量、结构体字段等),导致多个goroutine同时复用同一个WaitGroup实例。 sync.WaitGroup的设计是单次使用:完成Wait()后,不能再调用Add()并重新执行Wait(),否则会触发该panic。当多个goroutine同时对同一个WaitGroup执行Add()、Wait()操作时,就会出现“前一次Wait还未返回就被复用”的冲突。
解决方法
- 优先方案:每次使用新建WaitGroup实例:保持
var wg sync.WaitGroup在check函数内部,确保每个check调用都使用独立的WaitGroup实例,从根源避免复用冲突。 - 若必须复用(不推荐):需用
sync.Mutex互斥锁保护WaitGroup的所有操作(Add()、Wait()、Done()),确保同一时间只有一个goroutine操作该WaitGroup,且严格遵循“Add -> 启动goroutine -> Wait -> 重置(仅确认所有Done执行完毕后)”的顺序,但这种方式会削弱并发性能,不建议采用。
内容的提问来源于stack exchange,提问作者jx.wtj
相关产品推荐
相关产品推荐

