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

先向c1发送数据,为何偶现select先接收c2的情况?

Go中select语句的随机选择行为解析
package main

func m() {
    c1 := make(chan int, 1)
    c2 := make(chan int, 1)

    go func() {
        c1 <- 1
        c2 <- 1
    }()

    select {
    case <-c1:
    case <-c2:
        println("no way")
    }
}

func main() {
    for i := 0; i < 1000000; i++ {
        m()
    }
}

我们创建了两个带缓冲的Channel:c1和c2(缓冲大小为1)。在一个goroutine中依次向c1、c2发送数据,同时主goroutine通过select语句尝试从这两个Channel接收数据并退出。

多数情况下先发送c1就会先接收c1,但偶尔会出现先发送c1却先接收c2的情况,请问原因是什么?


这其实是Go语言select语句的既定设计行为导致的:

  • 首先,我们创建的是带缓冲(大小1)的channel,向这类channel发送数据时,只要缓冲未满,操作就是非阻塞的。所以子goroutine里的c1 <- 1和c2 <- 1会非常快地连续完成——快到主goroutine的select语句执行时,c1和c2两个channel都已经处于就绪状态(都有数据可以接收)。
  • 当select语句的多个case对应的channel都就绪时,Go语言的运行时会随机选择其中一个case执行,而不是严格按照代码里的书写顺序来优先选择第一个就绪的channel。

所以当两个channel都就绪时,select有一定概率选中case <-c2,这时候就会触发println("no way"),也就是你看到的“偶尔出现先发送c1却先接收c2”的情况。如果把循环次数调大,你会发现"no way"的打印次数大概接近总次数的一半(因为是随机选择,不会绝对精确)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:11:12