Go 为什么要去';s频道可以关闭两次吗?

Go 为什么要去';s频道可以关闭两次吗?,go,channel,Go,Channel,当我执行一些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 := &

当我执行一些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应用程序运行直到其主goroutine运行(给定“正常”情况),或者从另一个角度来看:Go应用程序在其主goroutine终止时终止,即
main()
函数返回。它不会等待其他非
main
goroutine完成

您开始了第二个goroutine,其中有一个没完没了的
for
循环,无法终止。因此,循环将一直进行,直到在并发的主goroutine中运行的
main()
函数返回。由于
for
循环首先接收来自
作业的
,因此它会等待主goroutine将其关闭(该接收操作只能随后继续)。然后,主goroutine希望从
done
接收数据,以便等待第二个goroutine发送一个值。然后主goroutine可以随时“自由”终止。运行循环的第二个goroutine可能会从
作业
接收到一个附加值,因为它已关闭,但随后在
完成
时的发送将被阻止,因为没有人再从它接收(并且它是无缓冲的)

通常使用范围的
完成从通道接收直到关闭,如果通道关闭,则退出:

for j := range jobs {
    fmt.Println("received: ", j)
    done <- true
}
j:=范围作业的
{
fmt.Println(“收到:”,j)

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

当goroutine启动时,它不会立即开始运行。相反,程序控件转到以下部分:

  close(jobs) // <--
  <- done
}

close(jobs)//进入频道不要关闭两次。你的传递完成了
  close(jobs) // <--
  <- done
}
j,more := <-jobs

fmt.Println("receive close: ", j, more)
done <- true
receive close:  0 false
receive close:  0 false
done <- true
j,more := <-jobs

fmt.Println("receive close: ", j, more)
receive close:  0 false