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

Go语言已关闭无数据Channel为何能在select中被接收?

为什么关闭的Channel在select中会持续触发计数?

这是个非常典型的Go Channel行为问题,咱们来拆解清楚:

核心原因:已关闭Channel的接收特性

在Go语言中,当你调用close(c)关闭一个Channel后:

  • 所有后续对该Channel的接收操作会立即返回,返回对应类型的零值,且不会发生阻塞。
  • 在select语句中,只要某个case的操作是「立即就绪」的,就有机会被选中执行;对于已关闭的Channel来说,接收操作永远处于就绪状态。

对应到你的代码分析

你的代码里做了这几件事:

  1. 创建了两个无缓冲Channel c1 和 c2,并立刻关闭了它们。
  2. 循环1001次(从1000到0),每次通过select尝试从两个Channel中接收数据。

因为两个Channel都已经关闭,它们的接收操作都是随时就绪的,Go的select会伪随机地选择其中一个就绪的case执行。所以每次循环都会触发其中一个计数器增长,最终两个计数器的总和刚好是1001(513+488=1001),而各自的数值是随机分配的——你多运行几次代码,会发现c1Count和c2Count的数值每次都不一样。

额外验证小实验

如果修改代码,只关闭其中一个Channel:

package main
import (
    "fmt"
)
func main() {
    c1 := make(chan interface{})
    close(c1)
    c2 := make(chan interface{})
    // 不关闭c2
    var c1Count, c2Count int
    for i := 1000; i >= 0; i-- {
        select {
        case <-c1:
            c1Count++
        case <-c2:
            c2Count++
        }
    }
    fmt.Printf("c1Count: %d\nc2Count: %d\n ", c1Count, c2Count)
}

运行后你会发现c1Count是1001,c2Count是0——因为未关闭的c2接收会阻塞,select只会选择就绪的c1 case。

内容的提问来源于stack exchange,提问作者Trần Kim Dự

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:56:53