无缓冲 channel 一发就死锁,因为其要求发送方和接收方必须同时就绪;main goroutine 单独发送而无接收者时,发送操作永久阻塞,触发 runtime 死锁检测并 panic。

Go 语言中 channel 阻塞不是 bug,而是设计使然——它本质是 goroutine 间同步的“握手机制”。但一旦发送和接收没配对、缓冲区失衡或逻辑遗漏,就会卡住甚至 panic。
无缓冲 channel 为什么一发就死锁?
因为无缓冲 channel 要求「发送方」和「接收方」必须同时就绪,缺一不可。main goroutine 单独 ch ,而没启动接收 goroutine,运行时立刻报 fatal error: all goroutines are asleep - deadlock。
- 典型错误:在
go func() { ... }()前忘了写go,或接收逻辑被if false意外跳过 - 调试技巧:用
go tool pprof http://localhost:6060/debug/pprof/goroutine?debug=2查看所有 goroutine 状态,一眼看出谁在等谁 - 修复思路:要么加
go启动接收者,要么改用带缓冲 channel(如make(chan int, 1)),但注意缓冲区满后仍会阻塞
select 里没写 default 就卡死?
是的。select 所有 case 都不可执行(比如所有 channel 都空/都满),又没 default 分支,整个 goroutine 就永久挂起——这不是死锁(runtime 不 panic),但效果一样:不动了。
- 常见场景:从多个 channel 读取,但某个 channel 始终没数据,也没设超时
- 非阻塞写法:
select { case v := - 限时等待写法:
case ,注意time.After返回的是,不能重复用
range 遍历 channel 却一直不退出?
因为 for range ch 会一直等新数据,直到 channel 被 close(ch)。如果发送方忘了关,或者关得太晚,接收方就永远卡在循环里。
立即学习“go语言免费学习笔记(深入)”;
- 关键规则:只有发送方能调用
close(ch);关闭后继续ch 会 panic;从已关闭 channel 读会得到零值 +ok==false - 安全模式:用
for v, ok := 替代range,显式检查ok - 切记:nil channel 也会阻塞——
var ch chan int后直接或ch ,goroutine 永久休眠
最易被忽略的点是:阻塞本身不可怕,可怕的是你以为它“应该不阻塞”。比如以为带缓冲 channel 就万无一失,结果缓冲区设成 1 却连续发 2 次,第二次照样卡;又比如用 sync.WaitGroup 时 Add() 写在 go 后面,导致 Done() 先执行、Wait() 永远等不到。这些都不是 channel 的问题,而是并发控制流没理清。










