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

简单Go程序运行报死锁,为何case balances <- balance分支未执行?

问题原因说明

你遇到的问题本质是无缓冲通道的发送就绪条件 + goroutine调度时序 + 带default的select非阻塞特性共同导致的:

  • 你声明的balances是无缓冲通道,无缓冲通道的发送操作要成功,必须同时有其他goroutine在该通道上等待接收值
  • 带default分支的select不会阻塞等待case就绪,会立刻判断当前所有case是否满足执行条件,不满足就直接走default
  • 执行到select代码块时,你启动的匿名子goroutine大概率还没被调度到<-balances这行代码,此时没有接收方在等待balances的发送,所以case balances <- balance:触发条件不满足,直接走了default分支
死锁的产生逻辑

走default分支之后,两个goroutine进入循环等待状态:

  • 主goroutine卡在<-done,等待子goroutine往done通道写入值
  • 子goroutine卡在<-balances,等待主goroutine往balances通道写入值
    所有goroutine都处于阻塞状态,Go runtime就会抛出死锁错误。
修复方案

你可以根据场景选任意一种方案修复:

  • 方案1:去掉select的default分支,让select阻塞等待通道就绪,等子goroutine调度到接收操作后,发送case会自动触发
// 修改select部分代码
select {
case balances <- balance:
    fmt.Println("done case")
}
  • 方案2:初始化balances时设置为长度1的带缓冲通道,就算接收方未就绪,发送方也可以先把值写入缓冲区,不会进入default分支
// 修改balances初始化代码
balances := make(chan int, 1)
  • 方案3:在select执行前添加短时间休眠,等待子goroutine调度到接收操作再执行select(仅用于理解调度时序,不推荐生产环境使用)
// 需先导入time包,在select前加如下代码
time.Sleep(time.Millisecond)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 21:39:02