Golang入站通道没有收到goroutine内部

时间:2014-08-16 14:20:58

标签: go channel

请帮助我理解为什么在这种情况下没有接收入境<-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 end
exit

但是它是:

enter
    wait start
  notify start
  notify end
exit

我最初假设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 个答案:

答案 0 :(得分:1)

当您使用睡眠时,它会为goroutine启动时间,然后在从通道读取时,主要退出前一个println(" wait end")被调用。

但是,如果你不打电话给睡眠,延迟将会阻止,直到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()
}

答案 1 :(得分:1)

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

done频道未缓冲:main

done := make(chan bool)

等待发送:go func()

<-done 

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

done <- true

main函数结束,不等待goroutine(go func())完成。

输出:

enter
    wait start
  notify start
  notify end
exit
  

The Go Programming Language Specification

     

Channel types

     

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

     

可以使用内置的新的初始化通道值   function make,它采用通道类型和可选容量   作为参数:

make(chan int, 100)
     

容量(以元素数量)设置缓冲区的大小   这个频道。如果容量为零或不存在,则通道为   无缓冲和通信只有当发送者和发送者都成功时才会成功   接收器准备好了。否则,通道被缓冲   如果缓冲区未满,则通信成功而不会阻塞   (发送)或不空(接收)。零通道永远不会准备好   通信。

     

Go statements

     

程序执行从初始化主程序包开始,然后   调用函数main。当该函数调用返回时,   程序退出。它不等待其他(非主要)goroutines   完整。