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

Go语言缓冲通道行为与预期不符,为何代码输出存在差异?

Go缓冲通道写入阻塞后仍输出16的原因分析

你的代码逻辑里,核心误解在于对goroutine阻塞和执行流程的判断,实际执行过程和预期有差异,具体拆解如下:

代码执行的完整流程

  1. 主goroutine启动,打印main() started,创建容量为3的缓冲通道c,随后启动squares goroutine。
  2. 主goroutine依次向通道写入1、2、3,此时通道被填满,没有空闲位置。
  3. 主goroutine执行c <- 4,因为通道已满,主goroutine进入阻塞状态,等待通道有接收者取走数据、腾出空间。
  4. 另一边,squares goroutine的循环是固定执行4次读取操作:
    • 前三次读取通道里的1、2、3,分别输出1、4、9,此时通道变为空。
    • 第四次循环时,squares执行num := <-c,通道为空,所以squares goroutine也进入阻塞状态,等待通道有数据写入。
  5. 当squares阻塞在第四次读取时,相当于给通道绑定了一个等待的接收者,此时主goroutine的c <-4阻塞被解除,4被写入通道的同时立即被squares读取,计算后输出16。
  6. squares完成4次循环后退出,主goroutine恢复执行,打印main() stopped。

为什么和预期不符?

你预期squares处理完前3个值后会因通道空而阻塞,程序直接结束,但实际上squares的循环是硬编码的i < 4,它会坚持执行第四次读取操作。这次读取操作会触发主goroutine的写入操作完成,所以第四个值4会被处理,输出16。

如果想达到预期输出(不含16)

有两种调整方式:

  • 把squares的循环次数改成i < 3,只处理3个值;
  • 让squares通过通道关闭来判断结束,主goroutine只写入1、2、3后关闭通道:
func squares(c chan int) {
    for num := range c {
        fmt.Println(num * num)
    }
}

func main() {
    fmt.Println("main() started")
    c := make(chan int, 3)
    go squares(c)

    c <- 1
    c <- 2
    c <- 3
    close(c)

    fmt.Println("main() stopped")
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 21:27:01