Go 教程:通道和缓冲通道

Go tutorial: Channels and Buffered Channels

为什么当第二个值通过另一个 go routine 发送并且第一个值没有收到时,通道 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)
}

我期待的是一个错误-

fatal error: all goroutines are asleep - deadlock!

当缓冲区已满时出现块时会出现这种情况。由于通道 c 的大小为 1,因此发送第二个值应该会出现上述错误。

上面的代码发生了什么?

仅仅因为写入不能立即成功,只要有其他 goroutine 可以 运行.

就不会出现“死锁”错误

让我们想象一个调度模型,其中 go 函数立即启动 goroutine 并在让步给其他人之前尽可能多地向前推进。那么会发生这样的事情:

  1. 程序会为列表的前半部分调用sum(),计算和,并尝试将其写入通道,但由于没有监听器,它会阻塞。
  2. 程序会为列表的后半部分调用sum(),计算和,并尝试将其写入通道,但由于没有监听器,它会阻塞。
  3. main() 将尝试从通道读取,唤醒之前的 goroutines 之一,并从中获取值。
  4. main() 将尝试从通道读取,唤醒另一个阻塞的 goroutine,并从中获取值。
  5. 没有人再阻塞通道输入或输出,所有 goroutines(包括 main())都可以 运行 完成。

如果你假装 go 只是在后台安排一些事情并继续 运行 主 goroutine,你可以做同样的练习。重要的是,只要在同一个通道上有成对的读写,两者都会继续。