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

移除quit通道发送语句后,Goroutine导致Go程序无法终止并报错的原因探究

关于Go Tour中Fibonacci通道代码的死锁问题解答

咱们先拆解下你遇到的问题,先梳理移除quit <- 0后的执行流程,再逐个解答你的疑问:

程序执行的核心流程

当你注释掉quit <- 0后,程序的执行步骤变成了这样:

  1. main函数创建c和quit两个无缓冲通道,启动匿名goroutine。
  2. 匿名goroutine循环5次,每次从c接收数据并打印,完成5次循环后,这个goroutine直接退出——它没有往quit发任何结束信号。
  3. main函数调用fibonacci(c, quit),进入这个函数的无限循环+select逻辑。

为什么会出现「所有goroutine都处于休眠状态」的致命错误?

这是Go runtime的死锁检测机制在起作用。Go要求程序中的所有goroutine必须能持续推进,当runtime发现所有goroutine都处于无法继续执行的阻塞状态时,就会抛出这个致命错误。

具体到你的代码:

  • 匿名goroutine已经执行完毕退出,不存在了。
  • fibonacci函数所在的goroutine:它的select一直在等待两个case中的一个能执行,但此时:
    • 第一个case c <- x:无缓冲通道的发送操作必须要有对应的接收者才能完成,但c的唯一接收者(那个匿名goroutine)已经消失,所以这个发送操作会永久阻塞。
    • 第二个case <-quit:quit通道从来没有被写入过数据,也没有被关闭,所以这个接收操作也会永久阻塞。
  • main函数:它在等待fibonacci函数返回,但fibonacci已经被阻塞住永远不会返回,所以main也处于阻塞状态。

此时整个程序的所有goroutine(main和fibonacci)都卡住了,没有任何一个能继续执行,runtime就判定为死锁,抛出错误。

「没有c通道的读取者,也没有更多代码语句需要执行」时实际发生了什么?

你说得没错,匿名goroutine确实已经完成了所有任务退出,但main函数和fibonacci goroutine还在运行:

  • main函数还在执行fibonacci(c, quit)这一行,它会一直等待fibonacci函数执行完毕返回,不会主动退出(哪怕main后面没有其他代码,它也会等子goroutine的函数调用完成)。
  • fibonacci goroutine则被卡在select语句上:它尝试往c发数据,但没人接收,又等不到quit的信号,所以完全停住,既无法执行x, y = y, x+y,也无法退出函数。

相当于两个goroutine各自卡住,整个程序彻底停摆。

如果quit通道永远不会触发,select的第一个case会一直无限循环吗?

不会的。无限循环的前提是select能不断执行第一个case,但这里的第一个case是c <- x——无缓冲通道的发送操作必须有接收者才能完成。当匿名goroutine退出后,c没有接收者了,这个发送操作就会阻塞,select会一直停在这个发送操作上,根本无法完成这个case的执行,自然也就不会执行后面的x, y = y, x+y,更不会进入下一次for循环。

简单说:select不是轮询两个case,而是等待任意一个case可以执行。当两个case都无法执行时,select就会一直阻塞,不会循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 05:02:48