为什么goroutines行政命令在两次运行之间是相同的
我有一个简单的围棋程序,其中有两个消费者频道同时从一个制作人那里读取数据,如下所示:为什么goroutines行政命令在两次运行之间是相同的,go,concurrency,goroutine,Go,Concurrency,Goroutine,我有一个简单的围棋程序,其中有两个消费者频道同时从一个制作人那里读取数据,如下所示: package main import "fmt" func main() { producer := make(chan int) wait := make(chan int) go func() { for i := 0; i < 1000; i++ { producer <- i } close
package main
import "fmt"
func main() {
producer := make(chan int)
wait := make(chan int)
go func() {
for i := 0; i < 1000; i++ {
producer <- i
}
close(producer)
wait <- 1
}()
go func() {
count := 0
for _ = range producer {
count++
}
fmt.Printf("Consumer 1: %i\n", count)
}()
go func() {
count := 0
for _ = range producer {
count++
}
fmt.Printf("Consumer 2: %i\n", count)
}()
<-wait
}
它在多次运行之间保持不变。有人能为我解释一下这种行为吗
环境:
go version go1.4.2 darwin/amd64
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/usr/local/go/:/Users/victor/Dropbox/projects/go/"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.4.2/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.4.2/libexec/pkg/tool/darwin_amd64"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"
Go编程语言规范中未定义Go goroutine调度算法。它是未定义的,因此它依赖于实现和版本。Go的当前实现使用协作调度方案。协作调度方案依赖于goroutines来执行不时地向调度器屈服的操作。调度程序代码位于包运行时中 该程序取决于通道操作 该程序还取决于硬件(例如,CPU数量)、操作系统和其他正在运行的程序 您的代码不应该期望goroutine调度中出现特定的分发 Go 1.4默认为GOMAXPROCS(1);对于Go 1.5及更高版本,它默认为NumCPU() 我已经修改了您的程序,以修复bug(附加等待语句),显示诊断信息,并在某些点向调度程序(Gosched())屈服。现在,该程序将在Go 1.6(devel-tip)、NumCPU()==8、GOMAXPROCS(8)和Go 1.5.1、NumCPU()==1、GOMAXPROCS(1)上密切复制您的结果。在紧循环中的某些点而不是在其他点向goroutine调度程序屈服,这是复制结果的关键
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println(runtime.Version())
fmt.Println(runtime.NumCPU())
fmt.Println(runtime.GOMAXPROCS(0))
producer := make(chan int, 100)
wait := make(chan int, 100)
go func() {
for i := 0; i < 1000; i++ {
producer <- i
runtime.Gosched()
}
close(producer)
wait <- 1
}()
go func() {
count := 0
for _ = range producer {
count++
}
fmt.Printf("Consumer 1: %d\n", count)
wait <- 1
}()
go func() {
count := 0
for _ = range producer {
count++
runtime.Gosched()
}
fmt.Printf("Consumer 2: %d\n", count)
wait <- 1
}()
<-wait
<-wait
<-wait
}
游乐场:
为便于比较,不作让步:
> go run noyield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 1: 81
Consumer 2: 919
> go run noyield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 1: 123
Consumer 2: 877
> go run noyield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 1: 81
Consumer 2: 919
> go run noyield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 2: 673
Consumer 1: 327
游乐场:
我没有输出。您从
go version
和go env
的输出是什么。我刚刚用您请求的信息更新了问题,所以我猜我的程序运行时使用的是1个CPU,2个使用者什么也不做,而不是增加计数器,速度太快,因此使用者1可能会在使用者2参与之前完成任务?你觉得@peterSO怎么样?我明白了,但我还是不明白为什么我的消费者总是667和333。即使使用1个CPU,也必须有一个明确的解释。@vutran:请参阅我修改后的答案。谢谢@peterSO,您的答案非常有用。我如何私下联系您?
> go run yield.go
8
8
Consumer 1: 668
Consumer 2: 332
> go run yield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 2: 336
Consumer 1: 664
> go run yield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 2: 333
Consumer 1: 667
>
go1.5.1
1
1
Consumer 1: 674
Consumer 2: 326
go1.5.1
1
1
Consumer 1: 674
Consumer 2: 326
go1.5.1
1
1
Consumer 1: 674
Consumer 2: 326
> go run noyield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 1: 81
Consumer 2: 919
> go run noyield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 1: 123
Consumer 2: 877
> go run noyield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 1: 81
Consumer 2: 919
> go run noyield.go
devel +54b4b94 Sat Feb 6 23:33:23 2016 +0000
8
8
Consumer 2: 673
Consumer 1: 327
go1.5.1
1
1
Consumer 1: 100
Consumer 2: 900
go1.5.1
1
1
Consumer 1: 100
Consumer 2: 900
go1.5.1
1
1
Consumer 1: 100
Consumer 2: 900