Go通道中发送者的排序

3
考虑一下来自http://www.golang-book.com/10/index.htm#section2的乒乓球例子。
package main

import (
    "fmt"
    "time"
)

func pinger(c chan string) {
    for i := 0; ; i++ {
        c <- "ping"
    }
}

func ponger(c chan string) {
    for i := 0; ; i++ {
        c <- "pong"
    }
}

func printer(c chan string) {
    for {
        msg := <- c
        fmt.Println(msg)
        time.Sleep(time.Second * 1)
    }
}

func main() {
    var c chan string = make(chan string)

    go pinger(c)
    go ponger(c)
    go printer(c)

    var input string
    fmt.Scanln(&input)
}

作者写道:

“该程序现在将轮流打印ping和pong。”

然而,为了使这成立,Go必须决定发送者可以按照什么顺序向通道发送数据?否则,就无法保证在发送pong之前会先发送ping(即你不能连续得到两个ping或两个pong)。这是如何实现的?

1
我的直觉是这个顺序只是巧合。但我猜peterSO会证明我错了。 - topskip
1
正确。这是使用通道的糟糕示例,甚至没有以任何方式进行乒乓(通常意味着调用+响应)。 - JimB
2
这不是巧合,而是由于发送过程除了发送以外几乎没有其他事情发生,而打印比发送需要更长的时间。当一个发送者发送并且通道清空时,另一个发送者已经准备好发送等待中,依此类推。这是 channels 作为同步机制的一个非常糟糕的例子,如果其中任何一个正在执行真正的工作,情况就不会是这样的。 - Not_a_Golfer
2个回答

7

pingpong Go协程之间没有同步,因此不能保证响应按顺序打印。

如果强制让Go协程在GOMAXPROCS>1时竞争,则会得到随机的输出:

pong
ping
ping
pong
ping
pong
ping
pong
pong

这甚至不是“乒乓”示例,因为没有呼叫和响应。


1

最近有一个相关问题,涉及消息进入通道的顺序。

答案是顺序通常是不确定的。这是故意的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接