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

Go通道行为是否受消息发送方式影响?两段代码执行差异答疑

Go通道常见问题解答

1. Go通道(channel)的行为是否会根据消息发送方式的不同而发生改变?

通道的核心行为由其是否带缓冲以及并发执行环境决定,和发送操作在哪个goroutine里执行无关。不管是主goroutine还是子goroutine发送数据,通道的阻塞规则是固定的:

  • 无缓冲通道:发送操作必须等到有接收方准备好接收才能完成,接收操作也必须等到有发送方准备好发送才能完成,双方是同步交互的。
  • 缓冲通道:只要缓冲队列没满,发送操作就能直接把数据存入队列而不阻塞;只要缓冲队列不为空,接收操作就能直接取出数据而不阻塞。

2. 两段Go代码执行结果不同的原因分析

代码①触发死锁的原因

这段代码创建的是无缓冲通道,在主goroutine里执行ch <- 1时,没有任何其他goroutine在等待接收这个数据,所以发送操作会一直阻塞主goroutine。而主goroutine被阻塞后,后续的fmt.Println(<-ch)根本没机会执行,整个程序里所有goroutine都陷入阻塞状态,Go运行时就会抛出fatal error: all goroutines are asleep - deadlock!错误。

如果把这段代码里的通道改成缓冲通道(比如make(chan int, 1)),缓冲队列能容纳一个元素,ch <- 1会直接把数据存入缓冲,不会阻塞主goroutine,后续的接收操作就能正常取出数据执行,程序也就不会死锁。

代码②能正常执行的原因

这段代码启动了一个子goroutine来执行buffer函数,主goroutine和子goroutine是并发运行的:

  1. 主goroutine执行第一个fmt.Println(<-ch)时,会阻塞等待数据。
  2. 子goroutine执行ch <- 2,此时主goroutine正在等待接收,发送操作完成,主goroutine收到数据后输出2。
  3. 主goroutine接着执行第二个fmt.Println(<-ch),再次阻塞等待数据。
  4. 子goroutine执行ch <- 3,此时主goroutine在等待接收,发送操作完成,主goroutine收到数据后输出3。

整个过程中,发送和接收操作是交叉同步完成的,没有出现所有goroutine都阻塞的情况,所以不会触发死锁。buffer函数里能发送两个值而不报错,是因为每次发送都有对应的接收操作在等待,发送操作不会一直阻塞,自然能顺利完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:45:14