ch 是 channel 的缩写,用于 go 语言中 select 语句里接收或发送数据,必须是已声明的 channel 类型变量。

select 中直接写 ch 会阻塞,怎么办?
不能直接在 select 的 case 里执行阻塞发送——如果通道满或无接收方,整个 select 就卡住。Go 不允许在 case 分支里写纯语句,必须是通信操作。所以得把发送包装成可立即返回、不阻塞的形态。
常见错误是试图这样写:
select {
case ch <p>真正可行的是用 <code>default</code> 配合带缓冲或非阻塞的发送逻辑,而匿名函数在这里只是封装手段,不是必需——关键在控制流结构。</p><h3>用 <code>default</code> + 匿名函数做“尝试发送”封装</h3><p>匿名函数本身不改变阻塞行为,但它能帮你把“尝试一次、失败就走”的逻辑收拢,避免重复写 <code>select</code> 块。典型模式是定义一个闭包,内部用 <code>select</code> + <code>default</code> 实现非阻塞发送:</p>
- 函数签名通常是
func(ch chan,返回是否成功发送 - 必须用
select+default,不能省略default,否则仍可能阻塞 - 注意:该函数只尝试一次,不重试,也不排队
示例:
sendNonBlocking := func(ch chan<h3>为什么不用 <code>go func() { ch ?</code>
</h3><p>这是常见误解:启个 goroutine 发送看似“不阻塞当前流程”,但带来新问题:</p>
- 无法知道发送是否成功(
ch可能已关闭,导致 panic) - goroutine 泄漏风险:若
ch永远没人接收,goroutine 永远挂起 - 数据竞争隐患:若
v是局部变量地址,goroutine 可能访问已释放内存 - 和
select无关——这根本没进select语义,只是绕开它
真正的非阻塞发送必须基于 select 的 default 分支,这是 Go 运行时保证的零等待机制。
缓冲通道和无缓冲通道对 default 行为的影响
default 是否触发,取决于通道当前状态,和是否有 goroutine 在等接收:
- 无缓冲通道:
case ch 仅当有 goroutine 正在 <code> 等待时才就绪;否则立刻走 <code>default - 缓冲通道:
case ch 在缓冲未满时就绪;满时走 <code>default - 通道已关闭:向已关闭通道发送会 panic,必须提前检查
cap(ch)或用recover(不推荐),更安全的是先用select尝试接收判断是否关闭
所以“非阻塞”不等于“总成功”,而是“不等、立刻决定”。实际使用中,要结合业务判断失败后是丢弃、重试还是降级处理。
真正容易被忽略的是:即使用了 default,也要考虑通道生命周期管理——比如 sender 和 receiver 的退出顺序,否则 default 频繁命中可能只是系统设计失衡的信号。











