如何完成例程交错?

时间:2015-03-15 19:08:42

标签: go goroutine

我感到惊讶的是,日常工作似乎完全交错......看到这一点后,我开始相信那些我尚未了解到的有关内部构件的信息。例如:

$ go run x.go > output
$ grep ping output | wc -l
404778
$ grep pong output | wc -l
404777
$ cat x.go 
package main
import (
    "fmt"
    "time"
)

type Ball struct{ hits int }

func main() {
    table := make(chan *Ball)
    go player("ping", table)
    go player("pong", table)

    table <- new(Ball) // game on; toss the ball
    time.Sleep(1 * time.Second)
    <-table // game over; grab the ball
}

func player(name string, table chan *Ball) {
    for {
        ball := <-table
        ball.hits++
        fmt.Println(name, ball.hits)
        //time.Sleep(1 * time.Millisecond)
        table <- ball
    }
}

无论您在播放器功能中设置超时(或将其全部删除),您总是得到#ping == #ping +/- 1。

3 个答案:

答案 0 :(得分:6)

您正在使用未缓冲的频道,而您的两个goroutines正在与之同步。对于未缓冲的通道,通道写入(table <- ball)只能在某个地方完成读取(<-table)后才能完成,因此单个goroutine永远无法读取它正在写入的值。这就是这个例子的重点。

答案 1 :(得分:1)

根据blog

Goroutines会为任何数量的玩家完美交错:

  

答案是因为Go运行时保持等待FIFO queue for receivers(goroutines准备在特定通道上接收),以及   在我们的情况下,每个球员在他传球后都准备好了   表

答案 2 :(得分:-5)

默认情况下,GOMAXPROCS设置为1,因此您会看到此行为。如果你增加GOMAXPROCS它将不再具有确定性。

请参阅this answer以获取示例

编辑@DaveC不同意,但是一个简单的测试显示不然。通道是同步的,但是执行的goroutines的顺序不是。这些是不同的概念。输入上面的代码,设置GOMAXPROCS&gt; 1并运行......

➜  tmp  export GOMAXPROCS=2
➜  tmp  go run balls.go
ping 1
pong 2
➜  tmp  go run balls.go
pong 1
ping 2
➜  tmp

正如您在上面所看到的,执行的goroutines顺序不是确定性的