当我执行一些go实践代码时,遇到一个问题,通道可以关闭两次,如下所示:
// jobs.go package main import ( "fmt" ) func main() { fmt.Println("Hello, playground") jobs := make(chan int, 5) done := make(chan bool) go func() { for { j,more := <-jobs fmt.Println("receive close: ", j, more) done <- true } }() close(jobs) <- done }
输出:
~ go run jobs.go Hello, playground receive close: 0 false receive close: 0 false
但是,当我手动关闭通道两次时,我得到了panic: close of closed channel。
panic: close of closed channel
为什么上面的代码可以两次关闭?
一个通道只能关闭一次,尝试关闭一个已关闭的通道紧急情况。
但接收从封闭通道没有限制,从关闭信道接收:
封闭通道上的接收操作始终可以立即进行,在接收到任何先前发送的值之后,得出元素类型的零值。
Go应用程序运行直到其主要goroutine运行(在“正常”情况下)为止,或者从另一个角度来看:Go应用程序在其主要goroutine终止(即main()函数返回)时终止。它不等待其他非main例程完成。
main()
main
您启动了具有无限for循环的第二个goroutine ,无法终止。因此,该循环将继续进行,直到main()在并发的主goroutine中运行的函数返回为止。由于for循环首先从接收jobs,因此它将等待主goroutine将其关闭(此接收操作只能继续进行)。然后,主要goroutine希望从中接收信息done,以便等到第二个goroutine在其上发送一个值。然后,主goroutine是“自由的”以随时终止。由于循环jobs已关闭,因此运行循环的第2个goroutine可能会收到一个附加值,但随后的send on done会阻塞,因为不再有任何人从该接收(并且它没有缓冲)。
for
jobs
done
通常使用来完成从通道接收直到关闭的操作for range,如果通道关闭则退出:
for range
for j := range jobs { fmt.Println("received: ", j) done <- true }
当然,这将在您的情况下造成死锁,因为永远不会到达循环主体,因为没有人发送任何东西jobs,因此循环永远不会进入其主体以发送值,done而这正是主要goroutine等待的。