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

Golang中WaitGroup与Channel结合使用的程序故障排查

代码问题分析

1. WaitGroup 计数不匹配

你启动了3个popMessage goroutine,但仅调用wg.Add(2),这会引发核心问题:

  • 当第二个goroutine因channel阻塞无法执行wg.Done()时,wg.Wait()会一直等待剩余计数完成,直接导致程序死锁。
  • 若后续goroutine全部执行完成,wg.Done()被调用3次,超出Add的计数,还会触发WaitGroup内部panic。

2. Channel 阻塞引发的连锁死锁

你创建的channel c缓冲容量仅为1:

  • 第一个goroutine执行c <- *i时,缓冲有空位,顺利完成解锁并调用wg.Done();
  • 第二个goroutine加锁后执行c <- *i,此时缓冲已被占满,会阻塞在发送操作上,且互斥量未解锁;
  • 第三个goroutine因等待互斥量解锁,全程无法推进;
  • 最终wg剩余计数未完成,wg.Wait()无限等待,程序彻底卡死。

3. 未关闭 Channel 导致后续阻塞

即便修复前两个问题,最后的for x := range c循环也会一直阻塞——range遍历channel时,只有当channel被关闭且所有数据读取完成后才会退出,而你的代码从未关闭c。

修复建议

  • 对齐wg.Add()数量与goroutine数量:这里应改为wg.Add(3);
  • 在所有goroutine完成后关闭channel,让range循环能正常退出:
    wg.Wait()
    close(c) // 关闭channel,终止range遍历
    fmt.Printf("final %d\n", *intPtr)
    for x := range c {
        fmt.Printf("channel %d\n", x)
    }
    
  • 可将channel发送操作移到互斥锁外,避免锁被长时间占用:
    func popMessage(wg *sync.WaitGroup, m *sync.Mutex, i *int, c chan<- int) {
        m.Lock()
        *i++
        val := *i
        m.Unlock() // 先解锁再发送,减少锁持有时间
        c <- val
        fmt.Printf("pop %d\n", val)
        wg.Done()
    }
    

内容的提问来源于stack exchange,提问作者Kendall Chenoweth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 01:02:37