Go 中的无缓冲通道

Pau*_*uli 4 go

这是一个关于无缓冲通道的简单示例代码:

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 中)。

sbe*_*rry 6

无缓冲通道阻塞发送,直到接收器准备好读取。在您的第一个示例中,首先设置了阅读器,因此当发送发生时,它可以立即发送。

在您的第二个示例中,发送发生在接收器准备就绪之前,因此发送阻塞并且程序死锁。

您可以通过创建缓冲通道来修复第二个示例,但是您有可能永远看不到 goroutine 的输出,因为程序可能会在输出缓冲区刷新之前退出(主 goroutine)。在被调度之前,goroutine 甚至可能不会作为主出口运行。