Go里面如何安全的关闭一个channel

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 保平安。
posted on 2026-07-20 09:31  朝阳1  阅读(6)  评论(0)    收藏  举报