1. 单个发送端,多个接收端(最简单)
func main() {
ch := make(chan int, 10)
// 唯一的发送端
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch) // 发送完毕,安全关闭
}()
// 多个接收端
for i := 0; i < 2; i++ {
go func() {
for v := range ch { // ch 关闭后,range 会自动退出循环
println(v)
}
}()
}
}
2: 多个发送端,单个/多个接收端(经典难题)
func main() {
dataCh := make(chan int, 100)
stopCh := make(chan struct{}) // 信号 channel
// 多个发送端
for i := 0; i < 3; i++ {
go func() {
for {
select {
case <-stopCh: // 收到停止信号,直接退出,不关闭 dataCh
return
case dataCh <- 42: // 尝试发送数据
}
}
}()
}
// 接收端(或控制中心)决定什么时候停止
go func() {
// 假设处理了 10 秒后决定停止
time.Sleep(10 * time.Second)
close(stopCh) // 安全地关闭信号 channel,广播给所有发送端
}()
}
3: 使用 sync.Once(适合不确定谁先退出的复杂场景)
type SafeChannel struct {
ch chan int
once sync.Once
}
func (sc *SafeChannel) Close() {
sc.once.Do(func() {
close(sc.ch)
})
}
总结
谁发送,谁关闭:只有在单发送端时适用。
多发送,控信号:用额外的 stopCh 广播停火命令,原 channel 靠 GC 回收。
不确定,用 Once:多处都有可能触发关闭时,用 sync.Once 保平安。