当通过另一个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,发送第二个值应该会出现上述错误。
以上代码中发生了什么?
答案 0 :(得分:1)
仅仅因为写操作无法立即成功,只要有其他可以运行的goroutine,您就不会出现“死锁”错误。
让我们想象一个调度模型,其中一个go
函数立即启动goroutine,并在屈服于其他人之前尽可能多地向前推进。然后会发生这种情况:
sum()
,计算总和,然后尝试将其写入通道,但是由于没有侦听器,它将阻塞。sum()
,计算总和,然后尝试将其写入通道,但是由于没有侦听器,它将阻塞。main()
将尝试从通道读取数据,唤醒以前的goroutine之一,并从中获取值。main()
将尝试从通道读取数据,唤醒另一个阻塞的goroutine,并从中获取值。main()
)都可以运行完毕。如果您假装go
只是在后台安排一些时间并继续运行主goroutine,则可以执行相同的练习。重要的是,只要在同一通道上进行成对的读写,两者都会继续进行。