进行教学:频道和缓冲频道

时间:2018-07-31 12:57:49

标签: go buffer channel channels

当通过另一个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,发送第二个值应该会出现上述错误。

以上代码中发生了什么?

1 个答案:

答案 0 :(得分:1)

仅仅因为写操作无法立即成功,只要有其他可以运行的goroutine,您就不会出现“死锁”错误。

让我们想象一个调度模型,其中一个go函数立即启动goroutine,并在屈服于其他人之前尽可能多地向前推进。然后会发生这种情况:

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

如果您假装go只是在后台安排一些时间并继续运行主goroutine,则可以执行相同的练习。重要的是,只要在同一通道上进行成对的读写,两者都会继续进行。