《Go语言圣经》关闭一个channel
func main() {
naturals := make(chan int)
squares := make(chan int)
// Counter
go func() {
for x := 0; x < 100; x++ {
naturals <- x
}
close(naturals)
}()
// Squarer
go func() {
for x := range naturals {
squares <- x * x
}
close(squares)
}()
// Printer (in main goroutine)
for x := range squares {
fmt.Println(x)
}
}
- 在Go语言中,当一个channel被关闭后,已经发送到该channel中的数据仍然可以被正常接收,直到所有数据都被处理完毕。
- 试图重复关闭一个channel将导致panic异常,试图关闭一个nil值的channel也将导致panic异常。关闭一个channels还会触发一个广播机制,
详细解释
在你的代码中:
- Counter协程向
naturals
channel发送0到99的整数,然后关闭该channel - Squarer协程使用
for x := range naturals
循环从naturals
接收数据 - 当
naturals
被关闭时:- 已经发送到
naturals
中的数据(0到99)仍然会被Squarer协程正常接收 for ... range
循环会继续处理这些数据,直到所有数据都被处理完毕- 只有当所有数据都被接收后,
for ... range
循环才会退出
- 已经发送到
关键点
- 关闭channel不会影响已发送的数据:关闭操作只是阻止后续的数据发送,不会影响已经在channel中的数据
for ... range
循环会处理所有已发送的数据:无论channel是否关闭,循环都会继续执行,直到所有数据被接收- 关闭是一种信号:关闭channel是向接收方发送一个信号,表示"不会再有新数据了",但已有的数据仍然有效
验证代码
以下代码可以帮助你验证这个过程:
package main
import "fmt"
func main() {
naturals := make(chan int)
squares := make(chan int)
// Counter
go func() {
for x := 0; x < 5; x++ {
naturals <- x
fmt.Println("Counter sent:", x)
// 添加延迟以便观察执行顺序
if x == 2 {
close(naturals)
fmt.Println("Counter closed naturals")
}
}
}()
// Squarer
go func() {
for x := range naturals {
squares <- x * x
fmt.Println("Squarer received:", x, "sending:", x*x)
}
close(squares)
fmt.Println("Squarer closed squares")
}()
// Printer
for x := range squares {
fmt.Println("Printer received:", x)
}
fmt.Println("Done")
}
输出示例
Counter sent: 0
Squarer received: 0 sending: 0
Printer received: 0
Counter sent: 1
Squarer received: 1 sending: 1
Printer received: 1
Counter sent: 2
Squarer received: 2 sending: 4
Printer received: 4
Counter closed naturals
Counter sent: 3
Squarer received: 3 sending: 9
Printer received: 9
Counter sent: 4
Squarer received: 4 sending: 16
Printer received: 16
Squarer closed squares
Done
总结
- 关闭channel后,已发送的数据仍然会被接收:在你的例子中,即使
naturals
被关闭,Squarer协程仍然会接收并处理0到99的所有数据 for ... range
是处理channel的安全方式:它会自动处理关闭状态,确保所有数据都被处理- 这是Go语言并发模型的设计亮点:简洁、安全,避免了常见的并发错误