使用频道时订购

Order while using channels

我有来自 Go tour 的代码:

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    fmt.Printf("Sending %d to chan\n", sum)
    c <- sum // send sum to c
}

func main() {
    s := []int{2, 8, -9, 4, 0, 99}
    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)
}

产生这个输出:

Sending 1 to chan
Sending 103 to chan
1 103 104

其中,x得到第二个和,y得到第一个和。为什么顺序颠倒了?

goroutines 的执行顺序没有保证。当您启动多个 goroutine 时,它​​们可能会或可能不会按您期望的顺序执行,除非它们之间存在显式同步,例如通道或其他同步原语。

在你的例子中,第二个 goroutine 在第一个 goroutine 之前写入通道,因为没有机制来强制两个 goroutine 之间的顺序。

类似于

如果你运行多次,它可能会给出不同的结果。当我 运行 我得到:

Sending 103 to chan
Sending 1 to chan
103 1 104

如果您希望结果是确定性的。您可以使用两个渠道:

func main() {
    s := []int{2, 8, -9, 4, 0, 99}

    c1 := make(chan int)
    c2 := make(chan int)
    go sum(s[len(s)/2:], c1)
    go sum(s[:len(s)/2], c2)

    x, y := <-c1, <-c2 // receive from c

    fmt.Println(x, y, x+y)
}

golang spec关于渠道的说法:

Channels act as first-in-first-out queues. For example, if one goroutine sends values on a channel and a second goroutine receives them, the values are received in the order sent.

如果将上述语句与 goroutines 执行的任意顺序结合起来,它可能会导致将项目排队到通道的任意顺序。


注意: 通道是 CSP.

的抽象