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

请求分析Go语言给定代码中存在死锁可能性的原因

Go语言死锁成因分析:你的代码哪里出问题了?

先直接点出核心问题:你的代码里发送方只发送了一次数据,但接收方尝试了两次接收,再结合无缓冲通道的特性,最终导致了死锁。咱们一步步拆解细节:

1. 发送端的逻辑局限

你在main函数里只启动了两个发送goroutine:

go reuters(reutersCh)  // 仅往reutersCh发送1次"REUTERS"
go bloomberg(bloombergCh)  // 仅往bloombergCh发送1次"BLOOMBERG"

这两个goroutine发送完数据就会直接退出,不会再产生任何新的发送操作。而reutersCh和bloombergCh都是无缓冲通道——无缓冲通道的核心规则是:发送和接收必须同时配对完成,否则操作会一直阻塞。

2. 接收端的重复调用触发死锁

你连续同步调用了两次newsReader(reutersCh, bloombergCh):

  • 第一次调用newsReader时,内部启动的两个匿名goroutine会分别尝试从两个通道接收数据。假设其中一个先拿到数据(比如reutersCh的内容),并把数据发到内部缓冲通道ch,随后x := <-ch拿到数据完成打印,第一次newsReader顺利执行完毕。此时另一个匿名goroutine也已经完成了对应通道的接收(因为发送方已经发了数据),并把内容存入了缓冲通道ch,但这个数据会因为newsReader退出而无人处理——不过这还不是死锁的直接原因。

真正的死锁发生在第二次调用newsReader:
第二次调用时,内部再次启动两个匿名goroutine,尝试从reutersCh和bloombergCh接收数据,但这两个通道的发送方早就已经发完数据退出了,没有任何goroutine会再往这两个通道发送内容。这两个匿名goroutine会永远阻塞在<-reutersCh和<-bloombergCh的接收操作上。

同时,main函数是同步调用newsReader的,它会一直等待第二次newsReader执行完毕,但newsReader里的x := <-ch永远拿不到数据(因为那两个接收goroutine都阻塞了,根本没法往ch里发数据),所以main也会陷入阻塞。整个程序的所有goroutine都无法继续执行,完全陷入阻塞状态,就触发了死锁。

3. 验证:只调用一次newsReader会怎样?

如果你把main里的第二次newsReader调用删掉,程序就能正常运行——发送端的一次发送刚好匹配接收端的一次接收,所有goroutine都能正常退出,不会出现阻塞。

4. 简单修复方案

如果需要多次调用newsReader,你需要保证每次接收都有对应的发送操作:

  • 方案一:每次调用newsReader时,都启动对应的发送goroutine
func main() {
    reutersCh := make(chan string)
    bloombergCh := make(chan string)
    // 第一次调用对应一次发送
    go reuters(reutersCh)
    go bloomberg(bloombergCh)
    newsReader(reutersCh, bloombergCh)
    // 第二次调用再启动一次发送
    go reuters(reutersCh)
    go bloomberg(bloombergCh)
    newsReader(reutersCh, bloombergCh)
}
  • 方案二:把发送端改成持续发送的模式(比如用循环),适配多次接收的场景

这样就能保证发送和接收的次数匹配,避免出现阻塞死锁的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 11:19:06