当我执行一些go实践代码时,遇到一个问题,通道可以关闭两次,如下所示:

输出:

但是,当我手动关闭两次通道时,得到了panic: close of closed channel

为什么上面的代码可以两次关闭?


一个通道只能关闭一次,尝试关闭一个已关闭的通道紧急情况。

但是从封闭渠道接收的信息不受限制,从封闭渠道接收信息是:

A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.

Go应用程序一直运行到它的主要goroutine运行(在"正常"情况下)为止,或者从另一个角度来看:Go应用程序在其主要goroutine终止时终止,即main()函数返回。它不等待其他非main goroutine的完成。

您启动了带有无限for循环且无法终止的第二个goroutine。因此,该循环将一直持续到main()函数(在并发的主goroutine中运行)返回。由于for循环首先从jobs接收,因此它等待主goroutine将其关闭(此接收操作只能继续进行)。然后,主goroutine希望从done接收,以便等到第二goroutine在其上发送值。然后,主goroutine处于"自由"状态,可以随时终止。由于循环已关闭,因此运行循环的第二个goroutine可能会从jobs接收一个附加值,但随后在done上的发送将被阻塞,因为不再有任何人接收到它(并且它没有缓冲)。

通常使用for range从通道接收直到关闭为止,如果通道关闭则退出:

当然,这将在您的情况下导致死锁,因为永远不会到达循环主体,因为没有人在jobs上发送任何内容,因此循环永远不会进入其主体以在done上发送值goroutine等待。


去通道不关闭twise。您的传递通过<-第一次打印后为true

所以印了两次

如果在打印之前使用done <-true,则它将仅打印一次,将关闭。

输出:


jobs通道没有关闭两次。调用close(jobs)时,它仅关闭一次。您看到的输出是由于goroutine和主线程如何执行的。

当goroutine触发时,它不会立即开始运行。而是,程序控制转到此部分:

并且jobs被关闭。然后,主线程挂在done的下一个接收器上。

现在发生上下文切换,goroutine开始运行。它从关闭的jobs读取,打印适当的值(morefalse表示关闭的通道),并沿着done发送true

但是,循环能够再次执行,并且goroutine块将在done上的下一次发送中发送。现在main再次唤醒,在done上接收并终止程序。