关闭 channel 后所有已发送但未接收的数据仍可被接收,直到 channel 为空;此后再接收将得到零值,且 ok 为 false。

关闭 channel 后所有 `
这是广播机制最直接的体现:只要 close(ch) 被调用,所有正在或即将执行 的 goroutine 都会被唤醒,且接收操作返回该类型的零值(如 <code>0、""、nil),同时 ok 为 false。
常见错误是只写 v := ,关闭后仍能读到零值,但无法区分“刚收到零值”和“channel 已关”。必须用双值接收才能安全判断:
if v, ok := <p>注意:多个 goroutine 同时阻塞在同一个 <code> 上时,<code>close(ch)</code> 会一次性唤醒全部,不是逐个通知。</code></p><h3>`for range ch` 自动终止依赖 channel 关闭</h3><p>当接收方使用 <code>for range ch</code> 语法时,它底层就是持续调用 <code> 并检查 <code>ok</code>。一旦 <code>ch</code> 被关闭,循环自动退出 —— 这是广播机制最常用也最容易被忽略的触发点。</code></p><p>如果发送方忘了 <code>close(ch)</code>,而接收方又在等 <code>for range</code> 结束,就会死锁:</p>
- 发送方只发完数据就退出,没关 channel
- 接收方卡在
for range,永远等待下一次接收 - 最终触发
fatal error: all goroutines are asleep - deadlock!
正确做法是:谁负责发送,谁在发完后调用 close(ch);接收方绝不能关别人创建的 channel。
用 `close(ch)` 实现多协程协同退出
关闭 channel 是轻量级的“全局信号”,适合做协程协作退出,替代手动传递 done 标志或轮询。
典型场景:
- 主协程启动一批 worker,用一个
shutdownCh统一通知停止 - 每个 worker 在
select中监听,收到 <code>ok=false就清理并退出 - 主协程只需
close(shutdownCh),无需遍历通知每个 worker
性能上无额外开销,比用带缓冲 channel 发送“退出指令”更干净 —— 没有数据传输,只有状态变更。但要注意:不能对已关闭的 channel 再次调用 close(),否则 panic。
广播 ≠ 多播:原生 channel 不支持一对多直接发送
很多人误以为 close(ch) 是“向多个接收者广播消息”,其实它广播的是“关闭信号”,不是业务数据。真正要发一条消息给多个 goroutine,必须自己中转:
- 不能把同一个
chan int同时交给 5 个 goroutine 去—— 它们会竞争消费,只有一人收到 - 若需真正广播,得用分发协程:监听一个中心
in chan interface{},再把每条消息复制发给每个注册的receiver chan - 此时
close(in)只影响分发协程,不影响各 receiver;想让 receiver 退出,得单独关它们各自的 channel 或发 sentinel 值
最容易被忽略的一点:关闭 signal channel 只解决“通知退出”,不解决“如何确保所有 receiver 已响应退出”。需要额外同步机制(如 sync.WaitGroup)来确认全部完成。











