go - 通道何时阻塞 goroutine
问题描述
如果我定义了一个没有缓冲区的通道并将一个数据写入其中,它会立即阻塞(以便内核将寻找另一个从通道读取的未阻塞 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 <-2 被执行时,goroutine 被阻塞(如果它没有被阻塞,fmt.Println 行将被执行,继续执行将在 <-c 处解锁 c)。当这个 goroutine 被阻塞时,内核会搜索其他 goroutine 并没有找到,所以它会报告死锁错误。
总之,在第一段代码中,我得出结论,写入通道不会立即阻塞 goroutine,而是从第二段代码开始。我在哪里弄错了,通道何时阻塞了 goroutine?
解决方案
发送到没有可用缓冲区空间的通道会阻塞发送方,直到发送完成;从没有可用消息的通道接收会阻塞接收器,直到接收可以完成。一个无缓冲的通道永远不会有缓冲空间——发送块直到接收到东西,反之亦然。这在围棋之旅中有所介绍:https ://tour.golang.org/concurrency/2
请记住,您的代码是并发的,因此您不能过多地阅读输出语句的顺序。可以在发送/接收操作和将消息打印到标准输出之间使 goroutine 进入睡眠状态。
推荐阅读
- c# - 在 asp.net core 3.0 中为角色 SecurityStamp 创建 ClaimsIdentityOptions
- javascript - 具有配置索引的数组在 ng-repeat 上不起作用,也不能在 AngularJS 的 html 中显示
- java - 如何保留我的距离表示分数字段并将其映射到我的结果实体中?
- python-3.x - 即使转到正确的路径,我也无法在 python 中打开文件
- javascript - 以任何方式将 JavaScript 文件链接到 HTML 文件都不起作用
- c++ - c++ MPI广播矢量
- javascript - 如何从javascript中的字符串中提取json
- r - R中的凸联合操作
- python - 如何修改我的函数以使用列表理解?
- xcode - Dropbox pod install 错误 - 需要更高的最低部署?