请帮助我理解为什么在这种情况下没有接收入境<-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)
}
答案 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
通道提供了一种同时执行函数的机制 通过发送和接收指定元素的值进行通信 类型。未初始化频道的值为零。
可以使用内置的新的初始化通道值 function make,它采用通道类型和可选容量 作为参数:
make(chan int, 100)
容量(以元素数量)设置缓冲区的大小 这个频道。如果容量为零或不存在,则通道为 无缓冲和通信只有当发送者和发送者都成功时才会成功 接收器准备好了。否则,通道被缓冲 如果缓冲区未满,则通信成功而不会阻塞 (发送)或不空(接收)。零通道永远不会准备好 通信。
程序执行从初始化主程序包开始,然后 调用函数main。当该函数调用返回时, 程序退出。它不等待其他(非主要)goroutines 完整。