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

Goroutines用time.Sleep正常,WaitGroup触发死锁?同步问题解析

为什么用sync.WaitGroup等待交替Goroutine会触发死锁,而time.Sleep不会?

死锁的根本原因(WaitGroup版本)

在无缓冲channel的场景下,两个goroutine的最后一次发送操作会引发阻塞链:

  1. f1完成第4次循环后,向ch2发送数据并调用wg.Done(),随后退出。
  2. f2完成第4次循环处理后,尝试向ch1发送数据,但此时ch1是无缓冲channel,且没有任何goroutine(主goroutine在wg.Wait()阻塞,f1已退出)准备接收这个值,导致f2阻塞在ch1 <- num*i,无法执行wg.Done()。
  3. 主goroutine一直等待两个wg.Done()调用,而f2永远无法完成任务,最终所有goroutine都进入阻塞状态,触发死锁。

time.Sleep与WaitGroup的行为差异

time.Sleep的工作逻辑

  • time.Sleep仅让主goroutine暂停指定时长,不关心其他goroutine是否执行完成。
  • 当睡眠时间结束,主程序直接退出,Go运行时会强制终止所有未完成的goroutine。即使此时f2可能还阻塞在发送操作,程序也不会触发死锁检测(因为进程已经退出)。
  • 你提供的time.Sleep版本额外使用了缓冲channel(大小1),这让最后一次发送操作不会阻塞,两个goroutine都能正常完成循环,程序自然无错误。

WaitGroup的工作逻辑

  • sync.WaitGroup的核心是等待所有注册的goroutine明确完成任务(即调用wg.Done())。
  • 主goroutine会一直阻塞在wg.Wait(),直到所有wg.Add()注册的计数被wg.Done()清零。
  • 如果任何一个goroutine因为channel阻塞无法调用wg.Done(),主goroutine会永远等待,最终触发死锁。

缓冲channel为什么能解决问题

当channel带有缓冲时,发送操作只要缓冲未被填满就不会阻塞:

  • f2最后一次向ch1发送数据时,缓冲channel可以容纳这个值,无需等待接收方,f2能顺利完成循环并调用wg.Done()。
  • 主goroutine收到两个wg.Done()后,wg.Wait()结束,程序正常退出,不会出现死锁。

内容的提问来源于stack exchange,提问作者Shubham Chadokar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:34:57