无缓冲 channel 一用就死锁,因其本质是同步握手,发送和接收必须同时就绪;若一方未就绪,协程立即阻塞,导致死锁。

无缓冲 channel 是同步握手,有缓冲 channel 是带仓库的异步管道——选错类型,轻则逻辑卡死,重则死锁 panic。
无缓冲 channel 为什么一用就死锁?
因为它的本质是“必须两人同时到场才能交接”,没人接,ch 就永远卡住;没人发,<code> 也一样。Go 运行时检测到所有 goroutine 都在等对方,就会直接报 <code>fatal error: all goroutines are asleep - deadlock!。
- 常见错误现象:主 goroutine 单独写
c := make(chan int); c ,没开 goroutine 去收,立刻死锁 - 正确用法必须成对出现:一个 goroutine 发,另一个 goroutine 收,且两者要“碰上”
- 典型场景:任务完成通知(
done := make(chan struct{}))、启动协调(子 goroutine 启动后发信号,主 goroutine 等它就绪) - 别把它当“队列”用——它存不了数据,只做同步点
有缓冲 channel 的容量不是越大越好
缓冲区大小设为 n,意味着最多能缓存 n 个值,但这也悄悄埋下两个隐患:内存占用和语义模糊。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 常见错误现象:设
make(chan int, 10000)后发现内存涨得快,或消费者宕机后生产者还在狂塞,最终 goroutine 积压 - 容量应基于真实吞吐差设计:比如消费者平均 10ms 处理一个任务,生产者峰值每 2ms 产一个,那缓冲区撑住 5 个就足够应对毛刺
- 发送不阻塞 ≠ 安全:向已满 channel 再发会阻塞,如果没配超时或 select default,照样卡死
- 关闭后继续 send 会 panic,但 receive 会返回零值 +
false,这点和无缓冲一致
怎么一眼判断该用哪种?看通信意图
不是看“要不要快”,而是看“要不要等”。关键在你写的这行 ch 或 <code>,是否**必须**和另一端严格对齐。
立即学习“go语言免费学习笔记(深入)”;
- 需要信号化、阻塞等待结果、确保某事已发生 → 用无缓冲:
ready := make(chan bool),子 goroutine 做完ready ,主 goroutine <code> 才往下走 - 生产节奏和消费节奏不同频,或想削峰填谷 → 用有缓冲:
jobs := make(chan Task, 10),多个 worker 并发从里面取,调度器不用停等 - 不确定用哪个?先用无缓冲。它行为确定、易推理;真卡住了,说明你漏了接收方——这是好问题,不是坏设计
- 慎用
make(chan T, 0):它和make(chan T)行为完全一样,但语义迷惑,容易让人误以为“有缓冲”
缓冲区不是保险丝,也不是万能胶。它解决的是时间错位,不是逻辑错误。真正难的从来不是“怎么写”,而是“谁该等谁”——这个判断错了,再漂亮的 channel 也会变成死锁导火索。

















