我有一个去的程序如下。它启动NumberOfCPUs-1
goroutines并在每个goroutine内部更新全局变量x
。输出为x = 0
。
func main() {
var x int
threads := runtime.GOMAXPROCS(0)-1
for i := 0; i < threads; i++ {
go func() {
for {
x++
}
}()
}
time.Sleep(time.Second)
fmt.Println("x =", x)
}
如果我稍微改变一下程序,就像这样:
func main() {
var x int
threads := runtime.GOMAXPROCS(0)
for i := 0; i < threads; i++ {
go func() {
for {
x++
time.Sleep(0)
}
}()
}
time.Sleep(time.Second)
fmt.Println("x =", x)
}
x
将是一些随机的大值。
我认为它可能与goroutine调度程序有关。在第一种情况下,goroutine的数量小于cpu核心的数量,因此main
func可以与所有现有的goroutine一起执行。由于每个goroutine内部都没有进行系统调用,I / O或通道通信,因此goroutine调度程序将无法正常工作。并且因为goroutine没有被中断,更新的x
没有机会被写回来。
在第二种情况下,goroutine的数量等于cpu核心的数量,为了让main
func有机会运行,我在更新后time.Sleep(0)
放置x
。我想每次goroutine调度程序都会切换goroutine,更新的x
将被写回原来的内存位置。
有人能证实我的想法吗?有没有错过?
感谢。
答案 0 :(得分:4)
您有多个goroutine共享相同的变量x
,并且具有不同步的读取和写入。你有数据竞赛。因此,x
的结果未定义。使用选项-race
运行竞赛检测器。请参阅Introducing the Go Race Detector。
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
var x int
threads := runtime.GOMAXPROCS(0) - 1
for i := 0; i < threads; i++ {
go func() {
for {
x++
}
}()
}
time.Sleep(time.Second)
fmt.Println("x =", x)
}
输出:
$ go run -race race1.go
==================
WARNING: DATA RACE
Read at 0x00c420084010 by goroutine 7:
main.main.func1()
/home/peter/gopath/src/race1.go:15 +0x3b
Previous write at 0x00c420084010 by goroutine 6:
main.main.func1()
/home/peter/gopath/src/race1.go:15 +0x54
Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/race1.go:13 +0xb6
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/race1.go:13 +0xb6
==================
x = 24717968
Found 1 data race(s)
exit status 66
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
var x int
threads := runtime.GOMAXPROCS(0)
for i := 0; i < threads; i++ {
go func() {
for {
x++
time.Sleep(0)
}
}()
}
time.Sleep(time.Second)
fmt.Println("x =", x)
}
输出:
$ go run -race race2.go
==================
WARNING: DATA RACE
Read at 0x00c4200140d0 by goroutine 7:
main.main.func1()
/home/peter/gopath/src/race2.go:15 +0x3b
Previous write at 0x00c4200140d0 by goroutine 6:
main.main.func1()
/home/peter/gopath/src/race2.go:15 +0x54
Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/race2.go:13 +0xb3
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/race2.go:13 +0xb3
==================
==================
WARNING: DATA RACE
Read at 0x00c4200140d0 by goroutine 8:
main.main.func1()
/home/peter/gopath/src/race2.go:15 +0x3b
Previous write at 0x00c4200140d0 by goroutine 6:
main.main.func1()
/home/peter/gopath/src/race2.go:15 +0x54
Goroutine 8 (running) created at:
main.main()
/home/peter/gopath/src/race2.go:13 +0xb3
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/race2.go:13 +0xb3
==================
x = 14739962
Found 2 data race(s)
exit status 66