当前位置: 首页 > 面试题库 >

为什么Go的频道可以关闭两次?

欧旻
2023-03-14
问题内容

当我执行一些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

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


问题答案:

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

但接收从封闭通道没有限制,从关闭信道接收:

封闭通道上的接收操作始终可以立即进行,在接收到任何先前发送的值之后,得出元素类型的零值。

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

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

通常使用来完成从通道接收直到关闭的操作for range,如果通道关闭则退出:

for j := range jobs {
    fmt.Println("received: ", j)
    done <- true
}

当然,这将在您的情况下造成死锁,因为永远不会到达循环主体,因为没有人发送任何东西jobs,因此循环永远不会进入其主体以发送值,done而这正是主要goroutine等待的。



 类似资料:
  • 关闭通道的意思是该通道将不再允许写入数据。这个方法可以让通道数据的接受端知道数据已经全部发送完成了。 package main import "fmt" // 在这个例子中,我们使用通道jobs在main函数所在的协程和一个数据 // 接收端所在的协程通信。当我们数据发送完成后,我们关闭jobs通道 func main() { jobs := make(chan int, 5) d

  • 关闭RSS频道 停止内容之播放后,于显示频道一览时按下按钮。 提示 关闭RSS频道之行为并无法同时切断网络联机。若想切断联机,请将无线LAN按钮调整为OFF(关)。

  • 问题内容: 在Java 8中,Stream类实现AutoCloseable。这意味着应显式关闭流实例。 我了解为什么文件处理程序和数据库连接是可关闭的。但是为什么要流? 问题答案: 我认为Stream的当前文档/ javadoc 非常清楚: 流具有BaseStream.close()方法并实现AutoCloseable,但是实际上几乎所有流实例在使用后都不需要关闭。通常,只有源是IO通道的流(例如

  • 问题内容: 据我所知,默认情况下,转到频道的行为就像一个队列,先进先出。有什么方法可以改变它们以先进先出吗? 基本上,我正在执行搜索,并且想对内存限制使用DFS而不是BFS。 问题答案: 不,这是不可能的-通道始终是FIFO。您可以使用package 。

  • 问题内容: 按照目前的情况,这个问题不适合我们的问答形式。我们希望答案会得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意调查或扩展讨论。如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 8年前关闭。 我知道它还为时过早,但是我一直在尝试Go(Google的编程语言)及其在gedit中编写代码的烦人方式。 所以,我的问题是:您如何使用Go进行实验? 问题答案

  • 我在看Tomcat的Java源代码,发现了这样的代码 它编译成功,而通常赋值应该是 为什么第一段代码编译成功?