【问题标题】:Order while using channels使用渠道时订购
【发布时间】:2019-10-20 23:38:45
【问题描述】:

我有这个来自 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 获得第一个总和。为什么顺序颠倒了?

【问题讨论】:

  • 以下多个答案的 TL;DR 是:一旦数据进入 通道,它就会被排序,但是您正在执行 put-data-into-channel in goroutine 执行顺序,不受控制,可能是并行的,而且无论如何都不是很可预测。

标签: go channel


【解决方案1】:

类似于goroutines order of execution

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

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)
}

【讨论】:

    【解决方案2】:

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

    在您的情况下,第二个 goroutine 在第一个之前写入通道,因为没有强制两个 goroutine 之间排序的机制。

    【讨论】:

      【解决方案3】:

      golang spec 谈到频道:

      通道充当先进先出队列。例如,如果一个 goroutine 在通道上发送值,第二个 goroutine 接收 它们的值是按照发送的顺序接收的。

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


      注意:频道是CSP的抽象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-15
        • 2012-11-02
        • 2016-01-12
        • 1970-01-01
        • 2020-11-28
        • 2021-12-03
        • 2019-10-24
        • 2017-11-19
        相关资源
        最近更新 更多