为什么Go的频道可以关闭两次? [英] Why Go's channel can close twice?
问题描述
循环,无法终止。所以这个循环会一直持续到
当我做一些实践代码时,我遇到了一个问题, // jobs.go
包裹主要
进口(
fmt
)
func main(){
fmt.Println(Hello,playground)
工作:= make(chan int,5)
完成:= make(chan bool)
去func (){
for {
j,more:=< -jobs
fmt.Println(receive close:,j,more)
done< -
$(
$ b $
输出:
〜go run jobs.go
您好,游乐场
收到关闭:0 false
收到关闭:0 false
但是,当我手动关闭频道两次时,我得到了
panic:关闭了频道
。
为什么上面的代码可以接收两次?
频道只能关闭一次,试图关闭一个封闭的频道恐慌。
A接收在关闭频道上进行的操作始终可以立即进行,产生元素类型的 zero value 。
Go应用程序一直运行到其主要的goroutine运行(给定正常情况),或者从另一个角度来看:Go应用程序在其主要goroutine终止时终止,也就是main()
函数返回。它不会等待其他非main
goroutines来完成。
你开始了第二个goroutine, code> for
main()
函数 - 它运行在并发的主函数返回中。由于循环首先从
作业
接收,它等待主协程关闭它(此接收操作只能然后继续)。然后主要的goroutine希望从done
接收,等到第二个goroutine发送一个值。然后主办公室随时自由终止。运行循环的第二个goroutine可能会从作业
中收到一个附加值,因为它已关闭,但随后发送done
将会因为没有人接收它(而且它没有缓冲)。
从频道接收直到关闭为止,通常使用
完成,范围
,如果频道关闭,则退出:对于j:=范围作业{
fmt.Println(received:,j)
完成< - true
}
当然这会在你的情况下导致死锁,因为循环体永远不会被触及,因为没有人在
作业
中发送任何东西,所以循环永远不会进入它的主体在done
上发送一个值,这是主要的goroutine等待的。When I am do some go practices code, I encounter a problem that a channel can be closed twice like this:
// 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 }
Output:
~ go run jobs.go Hello, playground receive close: 0 false receive close: 0 false
But when I close the channel twice manually, I got
panic: close of closed channel
.Why the code above can receive close twice?
解决方案A channel can only be closed once, attempting to close a closed channel panics.
But receiving from a closed channel is not limited, receiving from a 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.
A Go app runs until its main goroutine runs (given "normal" circumstances), or from another point of view: a Go app terminates when its main goroutine terminates, that is, the
main()
function returns. It does not wait for other non-main
goroutines to complete.You started a 2nd goroutine with an endless
for
loop, with no way of terminating. So that loop will keep going until themain()
function –which runs in the concurrent, main goroutine– returns. Since thefor
loop first receives fromjobs
, it waits for the main goroutine to close it (this receive operation can only then proceed). Then the main goroutine wants to receive fromdone
, so that waits until the 2nd goroutine sends a value on it. Then the main goroutine is "free" to terminate at any moment. Your 2nd goroutine running the loop may receive an additional value fromjobs
since it's closed, but the subsequent send ondone
will block as there are nobody receiving from it anymore (and it's unbuffered).Receiving from a channel until it's closed is normally done using
for range
, which exits if the channel is closed:for j := range jobs { fmt.Println("received: ", j) done <- true }
Of course this would cause a deadlock in your case, as the loop body would never be reached as nobody sends anything on
jobs
, and so the loop would never enter its body to send a value ondone
which is what the main goroutine waits for.这篇关于为什么Go的频道可以关闭两次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!