为了账号安全,请及时绑定邮箱和手机立即绑定

Golang 入站通道未在 goroutine 内接收

Golang 入站通道未在 goroutine 内接收

Go
郎朗坤 2021-08-10 15:34:56
请帮助我理解为什么<-done在这种情况下没有接收入站频道?func main() {    done := make(chan bool)    println("enter")    defer func() {        println("exit")    }()    defer func() {        println("  notify start")        done <- true        println("  notify end")    }()         go func() {        println("    wait start")        <-done        println("    wait end")    }()    time.Sleep(time.Millisecond) // << when this is removed, it works.}我期待输出是:enter  notify start    wait start    wait end  notify endexit但它是:enter    wait start  notify start  notify endexit我最初假设done通道以某种方式被提前关闭或清理,但即使done是全局的,它也会导致相同的意外行为。不应该<-done阻塞直到done <- true发生?反之亦然?解决似乎我期望程序在退出之前等待所有 goroutine 完成。这是一个错误的假设。这是一个肮脏的解决方法:func main() {    done, reallydone := make(chan bool), make(chan bool)    println("enter")    defer func() {        <-reallydone        println("exit")    }()    go func() {        println("    wait start")        <-done        println("    wait end")        reallydone <- true    }()    defer func() {        println("  notify start")        done <- true        println("  notify end")    }()    time.Sleep(time.Millisecond)}
查看完整描述

2 回答

?
梵蒂冈之花

TA贡献1900条经验 获得超5个赞

当您使用 sleep 时,它为 goroutine 提供时间启动,然后当它从通道读取时, main 在最后一个println("    wait end")被调用之前退出。


但是,如果您不调用 sleep,defer 将阻塞,直到 goroutine 从中读取并为其提供足够的时间进行打印。


如果您将代码移动到不同的函数并从 main 调用它,它将按预期工作。


func stuff() {

    done := make(chan bool)

    println("enter")

    defer func() {

        println("exit")

    }()

    go func() {

        println("    wait start")

        <-done

        println("    wait end")

    }()

    defer func() {

        println("  notify start")

        done <- true

        println("  notify end")

    }()

}

func main() {

    stuff()

}


查看完整回答
反对 回复 2021-08-10
?
慕容708150

TA贡献1831条经验 获得超4个赞

done通道上的事件序列:“[当] 通道无缓冲时,只有当发送方和接收方都准备好时,通信才会成功。” 对于你的例子,


的done信道是无缓冲:main。


done := make(chan bool)

接收等待发送:go func()。


<-done 

接收就绪 ( <-done),发送:defer func()。


done <- true

该main函数结束,不等待够程(go func())结束。


输出:


enter

    wait start

  notify start

  notify end

exit

Go 编程语言规范

渠道类型

通道为并发执行函数提供了一种机制,通过发送和接收指定元素类型的值来进行通信。未初始化通道的值为 nil。

可以使用内置函数 make 创建一个新的初始化通道值,该函数将通道类型和可选容量作为参数:

make(chan int, 100)

容量(以元素数为单位)设置通道中缓冲区的大小。如果容量为零或不存在,则通道没有缓冲,只有当发送方和接收方都准备好时,通信才能成功。否则,如果缓冲区未满(发送)或非空(接收),则通道被缓冲并且通信成功而不会阻塞。一个 nil 通道永远不会准备好进行通信。

Go 语句

程序执行首先初始化主包,然后调用函数 main。当该函数调用返回时,程序退出。它不会等待其他(非主)goroutine 完成。


查看完整回答
反对 回复 2021-08-10
  • 2 回答
  • 0 关注
  • 237 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信