go中channel发送时阻塞是因为默认无缓冲且无人接收,此时发送操作会一直等待直到有goroutine执行接收。

channel 发送时阻塞,是因为没人在接收
Go 的 chan 默认是无缓冲的,ch 这一行会一直卡住,直到有另一个 goroutine 在同一 channel 上执行 <code>。这不是 bug,是设计——它天然强制同步协作。
常见错误现象:fatal error: all goroutines are asleep - deadlock,通常就卡在发送或接收这一行。
- 如果确定只有一端发、一端收,必须确保二者并发执行(比如用
go func() { ... }()启一个 goroutine 去接收) - 想避免阻塞?加缓冲:
ch := make(chan int, 1),这样最多能存 1 个值,发送不会立刻阻塞 - 缓冲大小不是性能越高越好:缓冲为
n意味着最多积压n个未处理数据,可能掩盖背压问题,也增加内存占用
用 select + default 避免 channel 操作永久阻塞
有些场景不能等——比如超时控制、非阻塞尝试发送/接收。硬写 ch 或 <code> 很危险,一旦没人配合就死锁。
正确做法是用 select 配合 default 分支:
select {
case ch
-
select里所有 channel 操作都是非阻塞检查;没匹配到任何 case 且有default,就立即执行default - 没有
default的select仍会阻塞,和单个 channel 操作一样危险 - 多个
case可能同时就绪?Go 会随机选一个,不保证顺序——别依赖执行次序
关闭 channel 后还能读,但不能再写
close(ch) 不是“销毁 channel”,只是发一个信号:这 channel 不再会有新值了。已发送但未被取走的值仍可读取。
常见错误现象:对已关闭的 channel 再调 ch ,直接 panic:<code>panic: send on closed channel。
- 只应在**发送方**调
close(),且确保不会再往里塞数据 - 接收方用
v, ok := 判断是否关闭:<code>ok为false表示 channel 已关且无剩余数据 - 关闭 nil channel 也会 panic,所以关之前最好确认
ch != nil
nil channel 在 select 中永远不可达
把 nil 赋给一个 channel 变量后,它在 select 里既不会触发发送也不会触发接收——相当于这个 case 被静默忽略。
这常被用来动态开关某个通信路径:
var ch chan int // ……条件满足后 ch = make(chan int) // 然后 select 才可能命中 ch 相关的 case
- 向
nil chan发送或接收,会永久阻塞(不是 panic),非常难排查 - 用
select时若某个 channel 可能为nil,要提前判断,或用default防住 - 调试时打印
fmt.Printf("%p", ch)可快速确认是不是nil(输出 0x0)
事情说清了就结束。channel 的行为全由“谁在等、等什么、有没有缓冲、关没关”这四件事决定,其余都是这些组合出来的现象。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











