default 分支使 select 非阻塞——当所有 channel 均不可读/写时立即执行 default 并继续;否则 select 会阻塞等待就绪。它是 go 官方推荐的非阻塞通道操作方式,比 len(ch) 或 cap(ch) 更可靠。

select 里 default 分支到底干啥用
它让 select 不阻塞——只要所有 case 的 channel 都不可读/不可写,就立刻执行 default,然后往下走。没它的话,select 会卡住,直到某个 case 就绪。
典型场景:轮询多个 channel 时不想等,或者想做“试试看,不行就干别的”逻辑。
- 没有
default的select在无就绪 channel 时会 panic(如果在 goroutine 外且无其他分支)或永久挂起 -
default分支必须是纯非阻塞的;里面再写带select或time.Sleep就失去意义 - 哪怕只有一个
case,加default就从“等消息”变成“查一次状态”
非阻塞 recv / send 的标准写法
用 select + default 是 Go 官方推荐的非阻塞通道操作方式,比设 buffer=0 或用 len(ch) 更可靠。
注意:不能靠 len(ch) 判断能否 recv,因为 channel 可能被其他 goroutine 同时写入;也不能靠 cap(ch) 判断能否 send,因为可能刚被消费走一个空位。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 非阻塞 recv:
select { case v := - 非阻塞 send:
select { case ch
default 和 timeout 混用容易踩的坑
很多人想“等 100ms,超时就走 default”,结果写成 select { case ——这是错的。<code>default 会立刻抢跑,time.After 根本没机会触发。
-
default和time.After不能共存于同一select,否则default总是优先执行 - 真要带超时的非阻塞操作,去掉
default,只留case 和 <code>case - 如果既要“立刻试一次”,又要“失败后等一会儿重试”,得把
select+default包进循环,手动控制重试逻辑
default 分支里别偷偷阻塞
看着用了 default,以为整个 select 非阻塞,结果 default 里调了 http.Get 或 time.Sleep,整段逻辑又卡住了——这是最隐蔽的误用。
-
default分支本身不阻塞,但它里面的代码可以阻塞;是否非阻塞,取决于你写了什么 - 常见错误:在
default里启动 goroutine 却忘了用go,导致同步调用数据库或 API - 如果 default 里确实需要耗时操作,要么用
go func() { ... }()脱离当前流程,要么换思路:用带缓冲 channel 做任务队列,而不是在 select 里硬扛
事情说清了就结束
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










