Go语言两个goroutine对val各自增100次,最终结果总是200的原因是什么?
问题原因分析
首先明确:你提供的代码确实存在数据竞争,运行结果始终为200只是当前运行环境下的概率性表现,并非必然稳定的结果。具体原因如下:
val++本质是非原子操作,实际分为三步执行:读取val的当前值、值+1、将新值写回val。没有同步机制的情况下,如果两个goroutine的这三步执行发生重叠,就会出现两次自增实际只让val加1的问题,最终结果会小于200。- 你的代码中每次自增后都执行了
fmt.Printf打印和time.Sleep(5 * time.Millisecond)休眠操作,这两个操作都会触发Go调度器的调度,大概率让两个goroutine的自增操作完全错开:
单个goroutine执行完一次
val++后,会进入IO阻塞/休眠状态,调度器会切换到另一个goroutine执行,此时另一个goroutine执行自己的val++逻辑,两个goroutine的自增三步完全没有重叠,每次自增都能生效,所以最终结果刚好是200。
- 你可以通过修改代码验证数据竞争的存在:把
add函数里的打印和休眠逻辑删掉,再多次运行程序,就会出现最终结果小于200的情况。同时使用go run -race命令运行原代码,Go自带的竞争检测器也会明确报出数据竞争问题。
修改后的验证代码示例:
var val = 0 func main() { num := runtime.NumCPU() fmt.Println("使用cpu数量", num) go add("A") go add("B") time.Sleep(1 * time.Second) fmt.Println("val的最终结果", val) } func add(proc string) { for i := 0; i < 100; i++ { val++ // 移除打印和休眠逻辑 } }
内容的提问来源于stack exchange,提问作者space
相关产品推荐
相关产品推荐

