
“channel到底需不需要主动关闭?”这是很多Go开发者心中的疑问。根据我的多年开发的经验和理解,这篇文章和大家分享一下。
把channel想象成一个水管:
那么问题来了:水管用完后,需要手动关上阀门吗?
ch := make(chan int)
go func() {
for data := range ch { // 这个range在等ch关闭!
fmt.Println(data)
}
fmt.Println("工作完成")
}()
// ...发送一些数据后
close(ch) // 必须关闭,否则goroutine永远在等关键点:当接收方使用for range循环时,发送方必须关闭channel,否则接收方会一直阻塞等待。
// 广播通知所有等待的goroutine
close(shutdownChan) // 关闭后,所有 <-shutdownChan 都会立即返回虽然channel会被GC回收,但明确关闭可以立即释放相关资源,而不是等待GC。
func worker(ch <-chan int) { // 只读channel
// 你只负责接收,关闭是发送方的事
for data := range ch {
// 处理数据
}
}规则:谁创建/发送,谁负责关闭。接收方不应关闭channel。
done := make(chan bool)
go func() {
// 做某些事
done <- true
}()
<-done // 收到信号后,channel自然被GC回收
// 无需关闭,因为没有goroutine在等待它关闭如果channel只在单个goroutine内部使用,且没有其他goroutine在引用它,可以不关闭。
func producer(ch chan<- int) {
defer close(ch) // 函数退出前关闭
for i := 0; i < 10; i++ {
ch <- i
}
// 数据发完了,可以安心关闭
}开始
↓
是否有goroutine在使用 for range 等待这个channel?
↓ ↓
是 否
↓ ↓
必须关闭 ↓
其他goroutine是否在等待channel关闭?
↓ ↓
是 否
↓ ↓
必须关闭 可以不关闭for range在等待、要广播信号、想立即释放资源总结:关闭 channel 不是为了释放内存,而是为了发出“没有更多数据了”的信号。当你需要发送这个信号时,就关闭;不需要时,就让它自然消亡。