为什么在Go协程中递增共享的int变量时会显示原子行为?

huangapple go评论85阅读模式
英文:

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 &quot;fmt&quot;

const (
N_INCREMENTS = 10000000
)

func main() {

var counter int = 0
donechan := make(chan bool)

go func(done chan&lt;- bool) {
	for i := 0; i &lt; N_INCREMENTS; i++ {
		counter++
	}
	done &lt;- true
}(donechan)

for i := 0; i &lt; N_INCREMENTS; i++ {
	counter++
}

_ = &lt;-donechan

fmt.Println(&quot;Count: &quot;, 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(&quot;Previous GOMAXPROCS:&quot;, 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.

huangapple
  • 本文由 发表于 2015年11月15日 02:30:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/33711835.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定