为何向通道发送奇数个整数时Go程序才正常运行?
为什么Go程序仅在发送奇数个值到通道时才正常打印所有内容?
哇,这个现象确实有点让人摸不着头脑,我来帮你拆解下背后的逻辑——其实这和奇数/偶数本身没有直接关系,完全是Go程序的协程调度和生命周期规则导致的巧合。
首先先看你提供的代码:
package main import "fmt" func main() { ch := make(chan int) go Print(ch) for i := 1; i <= 12; i++ { ch <- i } close(ch) } func Print(ch <-chan int) { for n := range ch{ fmt.Println(n) } }
核心问题:main函数退出会终止所有协程
Go程序的运行规则是:一旦main函数执行完毕,整个程序就会立刻终止,所有正在后台运行的协程都会被强制停止,不管它们有没有完成任务。
在你的代码里,main函数做完这几件事就会退出:
- 启动
Print协程 - 把1到12(偶数个)全部发送到通道
- 关闭通道
问题就出在这里:close(ch)执行后,main函数没有等待Print协程把通道里的所有值都处理完,就直接结束了。这时候Print协程可能还在处理通道里的剩余值,就被程序终止了,导致部分值没打印出来。
为什么奇数个值的时候看起来“正常”?
这纯粹是Go调度器的随机巧合。当你发送奇数个值时,最后一次ch <- i执行后,main函数执行close(ch)的瞬间,调度器可能刚好切换到Print协程,让它把剩下的所有值都打印完;而发送偶数个值时,main函数可能在调度器切换到Print协程之前就已经退出了,导致部分值来不及打印。
这种行为是不确定的——你多跑几次代码,哪怕是发送奇数个值,也有可能出现打印不全的情况,只是概率更低而已,并不是奇数个值有什么特殊的“魔法”。
补充:如何确保所有值都被打印(仅作知识补充,不是作业解答)
如果你想让程序稳定地打印所有值,本质上是要让main函数等待Print协程完成任务。比如可以用sync.WaitGroup:
package main import ( "fmt" "sync" ) var wg sync.WaitGroup func main() { ch := make(chan int) wg.Add(1) go Print(ch) for i := 1; i <= 12; i++ { ch <- i } close(ch) wg.Wait() // 等待Print协程完成 } func Print(ch <-chan int) { defer wg.Done() for n := range ch { fmt.Println(n) } }
不过你提到不需要作业解决方案,所以重点还是理解前面说的调度巧合和协程生命周期规则。
内容的提问来源于stack exchange,提问作者user2468350
相关产品推荐
相关产品推荐

