如果我定义了一个没有缓冲区的通道并向其中写入一个数据,它会立即阻塞吗(以便内核将寻找从该通道读取的另一个不受阻塞的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)
}
}
Run Code Online (Sandbox Code Playgroud)
输出是这样的:
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
Run Code Online (Sandbox Code Playgroud)
在第一次写入c之后,由于已打印“将数字0插入通道”,因此似乎继续执行该例程。
代码2:
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
Run Code Online (Sandbox Code Playgroud)
由于在运行时报告了死锁错误,所以这段代码无法正确运行。
fatal error: all goroutines are asleep - deadlock!
Run Code Online (Sandbox Code Playgroud)
在我看来,执行c <-2时,goroutine被阻止(如果未阻止,则将执行fmt.Println行,而继续执行将在<-c处解锁c)。阻止此goroutine时,内核将搜索其他goroutine,但均未找到,因此将报告死锁错误。
总之,在第一段代码中,我得出结论,写到通道不会立即阻止goroutine,但是从第二段代码中会阻止。我在哪里弄错了,通道什么时候会阻塞goroutine?
发送到没有可用缓冲区空间的通道会阻塞发送方,直到发送完成为止。从没有可用消息的信道接收将阻塞接收器,直到接收完成。未缓冲的通道永远不会有缓冲空间-发送块直到有东西接收为止,反之亦然。围棋之旅涵盖了这一点:https : //tour.golang.org/concurrency/2
请记住,您的代码是并发的,因此您不能过多地理解输出语句的顺序。在发送/接收操作和将消息打印到标准输出之间,可以将goroutine置于睡眠状态。