go - Go 教程:通道和缓冲通道
问题描述
当通过另一个 go 例程发送第二个值并且未收到发送的第一个值时,为什么通道c没有缓冲出来?
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c ,<-c// receive from c
fmt.Println(x,y ,x+y)
}
我所期待的是一个错误-
致命错误:所有 goroutine 都处于休眠状态 - 死锁!
当缓冲区已满时出现块时,会发生这种情况。由于通道 c 的大小为 1,因此发送第二个值应该会给出上述错误。
上面的代码发生了什么?
解决方案
仅仅因为写入不能立即成功,只要有其他 goroutine 可以运行,您就不会出现“死锁”错误。
让我们想象一个调度模型,其中一个go
函数立即启动 goroutine,并在让步给其他人之前尽可能多地向前推进。然后会发生这种情况:
- 程序将调用
sum()
列表的前半部分,计算总和,并尝试将其写入通道,但由于没有侦听器,因此会阻塞。 - 程序将调用
sum()
列表的后半部分,计算总和,并尝试将其写入通道,但由于没有侦听器,它会阻塞。 main()
将尝试从通道读取,唤醒之前的 goroutine 之一,并从中获取值。main()
将尝试从通道读取,唤醒另一个阻塞的 goroutine,并从中获取值。- 没有人再阻塞通道输入或输出,所有的 goroutines(包括
main()
)都可以运行完成。
如果你假装go
只是在后台安排一些事情并继续运行主 goroutine,你可以做同样的练习。重要的是,一旦在同一通道上进行了配对读写,两者都会继续进行。
推荐阅读
- opencv - 使用 Open CV 识别深色矩形 - Node.js
- python - 需要pyspark中值大于0的列列表
- mysql - 在mysql中创建表后如何插入所有值?
- bash - 无法更改文件中的值
- google-cloud-firestore - agent.add 不工作,但 console.log 工作
- angular - angular 2+ 和 kendo angular 添加计算类
- flutter - Flutter Speech_recognition - IOS
- python - 机械化 Python Moodle 登录
- javascript - 如何在将 pixi.js 广告上传到谷歌时修复“html5 资产格式错误”?
- r - 修改函数,以便控制流构造使用“{...}”并将注释保留在正确的位置