英文:
Why shared int variable show atomic behavior when incrementing it in go routine?
问题
当我运行下面的代码片段时,它似乎总是打印出值20000000。当我创建更多的Go协程来增加计数器而没有加锁时,它显示出类似的行为。但是难道不应该存在某种竞争条件吗?谢谢!
package main
import "fmt"
const (
N_INCREMENTS = 10000000
)
func main() {
var counter int = 0
donechan := make(chan bool)
go func(done chan<- bool) {
for i := 0; i < N_INCREMENTS; i++ {
counter++
}
done <- true
}(donechan)
for i := 0; i < N_INCREMENTS; i++ {
counter++
}
_ = <-donechan
fmt.Println("Count: ", counter)
}
英文:
when I run the following code snippet below, it looks it always prints the value 20000000. It shows similar behavior when I create more go routines to increment the counter without lock. But shouldn't there exist some kind of race condition ? Thanks !
package main
import "fmt"
const (
N_INCREMENTS = 10000000
)
func main() {
var counter int = 0
donechan := make(chan bool)
go func(done chan<- bool) {
for i := 0; i < N_INCREMENTS; i++ {
counter++
}
done <- true
}(donechan)
for i := 0; i < N_INCREMENTS; i++ {
counter++
}
_ = <-donechan
fmt.Println("Count: ", counter)
}
答案1
得分: 1
runtime.GOMAXPROCS(0)
会告诉你可以并行运行的goroutine数量。如果值为1,你可能不会观察到不同步counter
变量的任何“副作用”。
如果在程序开始时将其设置为2
:
runtime.GOMAXPROCS(2)
你将立即看到效果:
Count: 10319575
如果你想要证明竞争条件,可以提供-race
参数。带有-race
的输出:
==================
警告:数据竞争
由goroutine 6读取:
main.main.func1()
V:/workspace/IczaGo/src/play/play.go:20 +0x48
之前由主goroutine写入:
main.main()
V:/workspace/IczaGo/src/play/play.go:26 +0xef
Goroutine 6(正在运行)创建于:
main.main()
V:/workspace/IczaGo/src/play/play.go:23 +0xbc
==================
(请注意,竞争检测器仅适用于64位Go发行版。)
在Go Playground上,默认情况下GOMAXPROCS为1
。这行代码将打印先前的值并将其设置为2
:
fmt.Println("Previous GOMAXPROCS:", runtime.GOMAXPROCS(2))
输出结果(在Go Playground上尝试):
Previous GOMAXPROCS: 1
Count: 12844130
还要注意,在1.5之前的Go发行版中,GOMAXPROCS默认设置为1
。从1.5开始,默认值为运行程序的计算机上可用的CPU核心数。
英文:
runtime.GOMAXPROCS(0)
will report you the number of goroutines that can be run parallel. If the value is 1, you may not observe any "side effect" of not synchronizing the counter
variable.
If first at the beginning of your program you set it to 2
:
runtime.GOMAXPROCS(2)
You will immediately see the effect:
Count: 10319575
If you want to have proof of the race condition, supply the -race
argument. The output with -race
:
==================
WARNING: DATA RACE
Read by goroutine 6:
main.main.func1()
V:/workspace/IczaGo/src/play/play.go:20 +0x48
Previous write by main goroutine:
main.main()
V:/workspace/IczaGo/src/play/play.go:26 +0xef
Goroutine 6 (running) created at:
main.main()
V:/workspace/IczaGo/src/play/play.go:23 +0xbc
==================
(Note that the race detector only works with 64-bit Go distributions.)
On the Go playground, GOMAXPROCS is 1
by default. This line will print the previous value and set it to 2
:
fmt.Println("Previous GOMAXPROCS:", runtime.GOMAXPROCS(2))
Output (try it on the Go Playground):
Previous GOMAXPROCS: 1
Count: 12844130
Also note that GOMAXPROCS is set to 1
in Go distributions prior to 1.5. Starting with 1.5 the default value of GOMAXPROCS is the number of CPU cores available on the machine running the program.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论