我感到惊讶的是,日常工作似乎完全交错......看到这一点后,我开始相信那些我尚未了解到的有关内部构件的信息。例如:
$ 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。
答案 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顺序不是确定性的