【发布时间】:2019-11-04 11:44:54
【问题描述】:
如果我定义了一个没有缓冲区的通道并将一个数据写入其中,它会立即阻塞(以便内核将寻找另一个从通道读取的未阻塞 goroutine),还是继续执行并在下一次时阻塞某些代码在尚未读取时尝试再次写入通道?
以下是我为研究这个问题而写的两段代码。
代码1:
package main
import "fmt"
func main() {
c := make(chan int)
go func() {
for i := 0;i < 3; i++ {
c <- i
fmt.Printf("number %v inserted into channel\n", i)
}
}()
for i := 0; i < 3; i++ {
fmt.Printf("number poped from channel %v\n", <-c)
}
}
输出是这样的:
number 0 inserted into channel
number poped from channel 0
number poped from channel 1
number 1 inserted into channel
number 2 inserted into channel
number poped from channel 2
在第一次写入 c 后,这个 goroutine 似乎继续执行,因为打印了“数字 0 插入通道”。
代码2:
package main
import "fmt"
func main() {
c := make(chan int)
c <- 2
fmt.Println("Something is written into channel")
<-c
}
由于运行时报死锁错误,这段代码无法正常运行。
fatal error: all goroutines are asleep - deadlock!
在我看来,当执行 c
总之,在第一段代码中,我得出结论,写入通道不会立即阻塞 goroutine,而是从第二段代码开始。我在哪里弄错了,通道何时阻塞了 goroutine?
【问题讨论】:
-
此外,IMO 的源代码可读性极强(因为它正在运行!!!:))golang.org/src/runtime/chan.go#L142
-
将接收分解为单独的变量
j := <-c可能有助于您理解(编译器很可能会自行执行此操作)。传递值后,fmt.Printf调用中的一个或两个都可以继续进行,并且不能保证哪个会先发生。