You need to enable JavaScript to run this app. 如何向Golang初学者清晰讲解channel阻塞运行机制?
优惠活动
大模型
产品
解决方案
定价
更多

如何向Golang初学者清晰讲解channel阻塞运行机制?

Go Channel 阻塞机制通俗讲解

核心基础规则

你测试用的是无缓冲channel(make(chan string)没有传入缓冲区大小参数),运行逻辑可以类比成「没有储物格的快递站」:

  • 送快递的(发送方)到了之后,必须等收快递的(接收方)当场来拿才能走,不能把快递放在站点,这就是发送阻塞
  • 收快递的(接收方)到了之后,也必须等送快递的(发送方)把货递到手里才能走,这就是接收阻塞

你看到的规则「sends and receives block until the other side is ready」就是这个意思:无缓冲channel的发送/接收操作,会让当前执行操作的goroutine停在这一行代码,直到对面的操作就绪才会继续往下跑。

死锁触发的前提非常明确:程序里所有活跃的goroutine全部处于阻塞状态,没有任何一个可以继续执行后续代码。


你的测试代码差异原因

main func 1 为什么不报错

你加了go关键字启动chanWrite,相当于开了一个独立的新goroutine去执行写入操作:

  1. main goroutine继续往下走,执行time.Sleep(time.Second)进入休眠,此时还属于活跃状态,不是阻塞
  2. 新启动的子goroutine跑到ch <- s时,因为没有接收方,确实卡在了这一行
  3. 1秒计时结束后,main goroutine休眠结束,main函数直接退出,整个程序终止,阻塞的子goroutine会被直接销毁,不会触发全阻塞的死锁条件。

main func 2 为什么报错

你没加go关键字,chanWrite是在main goroutine里同步执行的:

  1. 进入chanWrite后执行到ch <- s,此时没有任何其他goroutine会来读这个channel,main goroutine直接阻塞在这一行,后面的time.Sleep根本没机会执行
  2. 整个程序此时只有main这一个goroutine,还完全卡在写入操作上,没有任何能继续执行的代码,满足死锁触发条件,runtime就抛出了对应的fatal error。

常见疑问解答

  • 同一个goroutine在向channel写入数据后,可以执行该channel的读操作吗?
    对无缓冲channel来说不可能。你在同一个goroutine里执行写入操作的时候,这个goroutine已经被阻塞在写入这一行,根本跑不到后面的读代码。如果是带缓冲区的channel,缓冲区未满时写入不会阻塞,写完之后同一个goroutine可以正常读。
  • 如果一个channel处于阻塞状态,其他goroutine还能向它发送消息吗?
    首先不存在「channel处于阻塞状态」的说法,阻塞的是执行channel操作的goroutine,不是channel本身。如果已经有一个goroutine卡在往无缓冲channel写的操作上,其他goroutine再往同一个channel写,也会依次阻塞在写操作上,直到有接收方来读。
  • 如果goroutine尝试向已阻塞的channel发送消息,会发生什么?会报错还是无响应?
    还是上面的逻辑,阻塞的是goroutine不是channel。多个goroutine往同一个无缓冲channel写时,这些goroutine会排队阻塞,直到有接收方来取数据,runtime会调度第一个排队的发送方把数据传给接收方,对应的goroutine恢复运行。只有所有goroutine都阻塞在这个channel的操作上时,才会触发死锁报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 02:24:01