Golang 入站 channel 未在 goroutine 中接收

标签 go channel

请帮我理解为什么入站<-done在这种情况下没有接收到 channel ?

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 end
exit

但它是:

enter
    wait start
  notify start
  notify end
exit

我最初假设 done channel 以某种方式被提前关闭或清理,但即使在 done 时也会导致同样的意外行为。是全局性的。

不应该<-done阻止直到 done <- true发生?反之亦然?

决议

我似乎希望程序在退出之前等待所有 goroutines 完成。这是一个错误的假设。

这是一个肮脏的解决方法:

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)
}

最佳答案

当您使用 sleep 时,它会为 goroutine 提供启动时间,然后在它从 channel 读取时,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()
}

关于Golang 入站 channel 未在 goroutine 中接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25341047/

相关文章:

go - 捕获 Go 中的空格键而不跟随 Enter

golang channel 无法与 sync.WaitGroup 一起使用

Netty 的 `sync` 与 `syncUninterruptibly`

go - byte[] channel 使用

api - 使用 AppEngine Channel API 在多个窗口/选项卡上同步聊天

go - 应用程序的邮件系统之类的东西是否应该像本例所示那样在单独的 channel 中运行?

git - 如何创建 pull 请求或 merge PR

go - 如何使用golang创建嵌套的json数组对象

pointers - 当我 := &b 时 '&i' 是什么意思

go - 惯用的 goroutine 终止和错误处理