我有以下代码:
func writeToClosedBufferedChannel() {
ch := make(chan int, 2)
ch <- 10
ch <- 20
go func() {
fmt.Println("test")
ch <- 30
}()
time.Sleep(100 * time.Millisecond)
fmt.Println("before")
close(ch)
fmt.Println("after")
for value := range ch {
fmt.Println(value)
}
}
我的这段代码有不同的结果:
test
before
after
panic: send on closed channel
test
before
after
10
20
test
before
after
10
20
panic: send on closed channel
我知道,关闭后我无法写入频道,但为什么它会随机工作?我想检查一下,从 sendq 写入关闭通道后会发生什么,但现在我无法理解......
通道容量为2,因此10和20将被写入通道。 goroutine 将打印“test”,然后因为通道已满而阻塞。为了让它写入 30,另一个 goroutine 必须首先从通道读取。所以在测试之后,“before”和“after”也被打印出来,此时,你有一个关闭的通道,并且goroutine仍在等待写入通道。然后你开始从频道中阅读,可能会发生多种事情:
在您显示的第一个输出中,从通道中读取的第一个数据会解锁 goroutine,该 goroutine 由运行时调度并发送到关闭的通道,从而导致恐慌。
在第二个输出中,goroutine 被解除阻塞,但没有立即调度,因此主 goroutine 从通道读取两个值,程序终止。
在第三个输出中,goroutine 被解除阻塞,但仅在打印两个值之后、程序终止之前进行调度。