close(ch) 是最轻量标准的协程广播方式;关闭 chan struct{} 后所有

用 close() 关闭通道实现广播通知
关闭一个已声明的 chan struct{} 是最轻量、最标准的协程广播方式。Go 的 channel 关闭机制天然支持“单写多读”场景:所有从该通道接收的 goroutine 都会立即收到零值并继续执行,且后续接收操作永不阻塞。
关键点在于:你不需要向通道发送任何值,只需 close(ch),所有 就会立刻返回 struct{}{}(或任意类型通道的零值),配合 select 可自然退出循环。
- 必须使用无缓冲或带缓冲但已清空的
chan struct{}—— 它只承载“信号”,不传数据 - 只能由**单一协程**调用
close(),多次关闭 panic:panic: close of closed channel - 接收端不能仅靠
val := 判断是否关闭;必须用val, ok := ,ok == false才表示通道已关闭
在 select 中监听关闭通道并退出
这是最常见、最安全的协程协作退出模式。把关闭信号通道和业务逻辑通道一起放入 select,一旦收到关闭通知,就清理资源并 return。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
done := make(chan struct{})
go func() {
for {
select {
case msg :=
- 不要用
if 单独判断 —— 它会阻塞,且无法与业务通道并行等待 - 如果 worker 还在处理耗时任务,需额外加 context 或标志位做中断配合,
close(done)本身不中断正在运行的函数 - 多个 goroutine 可同时
select同一个done通道,无需锁或同步
为什么不用 chan bool 或带缓冲的 chan int
用 chan struct{} 是 Go 社区约定,不是语法强制,但它有明确优势:
-
struct{}占 0 字节内存,无论通道容量多大,都不额外消耗数据存储开销 - 编译器对
chan struct{}有优化,close()后的接收性能更稳定 -
chan bool容易让人误以为要 sendtrue/false,引发“谁来发?发几次?”的歧义;而close()语义唯一、不可逆 - 带缓冲通道(如
make(chan struct{}, 1))虽能避免关闭前没人接收导致的阻塞,但会掩盖漏监听的问题 —— 信号可能被缓存而未及时消费
注意:关闭通道 ≠ 立即终止 goroutine
通道关闭只是让接收操作不再阻塞,它不杀 goroutine,也不中断当前正在执行的函数。如果你的 worker 在 http.Serve()、time.Sleep() 或数据库查询中阻塞,close(done) 不会打断它。
- 长期阻塞操作必须配合可取消的原语:比如用
context.Context替代裸time.Sleep,用http.Server.Shutdown()替代粗暴 kill - 若 goroutine 内部有 for 循环 +
select,关闭done能让它退出循环;但若循环里没放select,或者select没包含done,那就完全收不到通知 - 没有“全局广播通道”这种东西 —— 你得把同一个
done chan struct{}显式传给每个需要响应的 goroutine
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










