这是一个关于无缓冲通道的简单示例代码:
ch01 := make(chan string)
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
fmt.Println("We are in the main goroutine")
ch01 <- "Hello"
Run Code Online (Sandbox Code Playgroud)
我得到的结果:
We are in the main goroutine
We are in the sub goroutine
Hello
Run Code Online (Sandbox Code Playgroud)
去游乐场:https : //play.golang.org/p/rFWQbwXRzGw
根据我的理解,发送操作阻塞了主协程,直到子协程在 channel 上执行了接收操作ch01。然后程序退出。
在像这样的发送操作之后放置子 goroutine 之后:
fmt.Println("We are in the main goroutine")
ch01 <- "Hello"
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
Run Code Online (Sandbox Code Playgroud)
发生了死锁:
We are in the main goroutine
fatal error: all goroutines are asleep - deadlock!
Run Code Online (Sandbox Code Playgroud)
去游乐场 https://play.golang.org/p/DmRUiBG4UmZ
这次发生了什么?这是否意味着在ch01 <- "Hello"主 goroutine 被立即阻塞以至于子 goroutine 没有机会运行之后?如果是真的,我应该如何理解第一个代码示例的结果?(首先在 main goroutine 中,然后在 sub goroutine 中)。
无缓冲通道阻塞发送,直到接收器准备好读取。在您的第一个示例中,首先设置了阅读器,因此当发送发生时,它可以立即发送。
在您的第二个示例中,发送发生在接收器准备就绪之前,因此发送阻塞并且程序死锁。
您可以通过创建缓冲通道来修复第二个示例,但是您有可能永远看不到 goroutine 的输出,因为程序可能会在输出缓冲区刷新之前退出(主 goroutine)。在被调度之前,goroutine 甚至可能不会作为主出口运行。