You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言Worker Pool添加WaitGroup后死锁的核心原因分析

分析Worker Pool死锁的核心原因

嗨,我来帮你拆解这个死锁问题的本质,其实问题就出在通道关闭时机和WaitGroup等待逻辑的配合上:

死锁的触发链条

  1. Worker的循环特性:你启动的每个worker goroutine都在执行for job := range JobChan,这个循环的规则是只有当通道被关闭且所有元素都被接收完毕时,才会退出循环。只要通道没关,worker就会一直阻塞在接收操作上,永远不会执行defer wg1.Done()(因为函数还没走到退出逻辑)。
  2. Main goroutine的阻塞点:当你把10000个任务全部发送到JobChan后,直接调用了wg.Wait(),此时main goroutine会阻塞在这里,等待所有worker调用Done()来完成WaitGroup的计数。
  3. 互相等待的死锁:一边是worker们盯着JobChan等新任务(永远等不到,因为任务已经发完了),不肯退出;另一边是main goroutine等着worker的Done()信号,不肯继续。双方都陷入了无限等待,最终触发死锁报错。

为什么不使用WaitGroup时程序“正常”?

其实那不是真的正常——当你去掉WaitGroup后,main goroutine在发送完所有任务后就直接退出了,Go程序会强制终止所有未完成的goroutine,所以worker还没来得及因为通道未关闭而阻塞,就被结束了。你看不到死锁,但这并不是正确的优雅退出逻辑。

修复方案

解决方法很简单:在所有任务发送完成后,关闭JobChan,让worker明确知道不会再有新任务进来,循环可以正常退出。修改后的关键代码片段如下:

// Create jobs pool
for _, job := range jobsArr {
    JobChan <- job
}
close(JobChan) // 取消注释,移到这个位置!
wg.Wait()

这样worker在接收完所有任务后,会因为通道关闭而退出循环,执行defer wg1.Done(),WaitGroup的计数归0后,main goroutine就能正常结束了。

内容的提问来源于stack exchange,提问作者Sammi Kerra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 11:57:36