Golang使用WaitGroups实现worker时触发all goroutines are asleep死锁问题
死锁触发原因
- 核心是执行顺序逻辑闭环:你的代码中
close(messageChannel)的位置放在了wg.Wait()之后,形成了双向等待的死锁:- worker的退出逻辑依赖
for range messageChannel终止:Go语言中for range遍历无缓冲/有缓冲channel时,只有channel被显式关闭且所有缓冲数据都被读取完毕,循环才会退出;如果channel未关闭且为空,worker会永久阻塞在遍历步骤,永远不会执行defer wg.Done() - main goroutine 执行到
stop(wg)时会卡在wg.Wait(),必须等所有worker的wg.Done()都执行完成,才会继续执行后续的close(messageChannel)逻辑
- worker的退出逻辑依赖
- 两边互相等待对方先执行操作,没有任何goroutine能继续推进逻辑,就触发了Go运行时的死锁检测,抛出对应的fatal error。
修复方案
将关闭channel的操作提前到wg.Wait()之前,发完全部任务后立刻关闭channel,通知worker没有更多任务需要处理:
func main() { wg := new(sync.WaitGroup) messageChannel := make(chan string, 50) for i := 0; i < 5; i++ { wg.Add(1) go worker(wg, messageChannel) } for i := 0; i < 10; i++ { messageChannel <- fmt.Sprint(i) } // 发完所有任务立刻关闭channel,通知worker退出 close(messageChannel) stop(wg) }
修复后执行逻辑:所有worker读完channel中缓存的10条任务后,检测到channel已关闭,自动退出for循环,执行defer wg.Done(),5个worker全部退出后wg.Wait()返回,程序正常退出。
内容的提问来源于stack exchange,提问作者shyam
相关产品推荐
相关产品推荐

