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

从main函数通过channel向多个goroutine发送值:谁先接收?

关于Go中多个Goroutine接收Channel值的顺序问题

嘿,我来帮你理清楚这个问题~首先先看你当前的代码,这里有个致命的死锁问题:你用的是无缓冲Channel,main函数里直接执行ch <- 1的时候,还没有任何Goroutine在等待接收这个Channel的值——你是先发送值,再调用receive函数启动Goroutine的,这会导致main Goroutine一直阻塞在发送操作上,程序直接死锁报错。

核心疑问:哪个Goroutine会最先收到Channel的值?

答案是:没有固定的确定性顺序,取决于两个因素:

  • 如果你的Goroutine里有延迟操作(比如代码里的time.Sleep),那哪个Goroutine先完成延迟、先执行到<-ch语句,哪个就会先收到值。
  • 如果没有任何延迟,多个Goroutine都在等待同一个无缓冲Channel时,Go的Runtime调度器会随机选择一个Goroutine来完成接收操作——这个选择逻辑是Runtime内部实现的,我们没法提前预测。

修正后的代码示例

我给你调整了代码,解决死锁问题,同时能更直观地看到接收顺序:

package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

func main() {
	rand.Seed(time.Now().UnixNano()) // 初始化随机数种子,让每次Sleep的时间更随机
	ch := make(chan int)
	var wg sync.WaitGroup

	// 先启动所有接收Goroutine
	for i := 0; i < 4; i++ {
		wg.Add(1)
		go func(goroutineID int) {
			defer wg.Done()
			// 随机延迟,模拟不同的执行节奏
			time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
			val, ok := <-ch
			if ok {
				fmt.Printf("Goroutine %d 收到了值: %d\n", goroutineID, val)
			} else {
				fmt.Printf("Goroutine %d 发现Channel已关闭\n", goroutineID)
			}
		}(i)
	}

	// 发送值到Channel
	ch <- 1
	// 关闭Channel,避免未接收的Goroutine一直阻塞
	close(ch)

	// 等待所有Goroutine执行完成,避免main提前退出
	wg.Wait()
}

补充说明

  • 我用了sync.WaitGroup来等待所有Goroutine执行完成,比time.Sleep更可靠,适合生产环境。
  • 如果你去掉代码里的time.Sleep,多次运行程序会发现每次接收的Goroutine ID都可能不一样,这就是Runtime调度器的随机性导致的。
  • 不管是无缓冲还是有缓冲Channel,当多个Goroutine等待接收时,Go语言都没有保证固定的接收顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:54:17