1 package main
2
3 import "time"
4
5 func main() {
6 m1 := make(map[string]int)
7 m1["hello"] = 1
8 m1["world"] = 2
9 go func() {
10 for i := 0; i < 100000000; i++ {
11 _ = m1["hello"]
12 }
13 }()
14 time.Sleep(100 * time.Millisecond)
15 m2 := make(map[string]int)
16 m2["hello"] = 3
17 m1 = m2
18 }
我使用此代码运行命令go run --race
并获取:
==================
WARNING: DATA RACE
Read at 0x00c420080000 by goroutine 5:
runtime.mapaccess1_faststr()
/usr/local/go/src/runtime/hashmap_fast.go:208 +0x0
main.main.func1()
/Users/meitu/test/go/map.go:11 +0x80
Previous write at 0x00c420080000 by main goroutine:
runtime.mapassign()
/usr/local/go/src/runtime/hashmap.go:485 +0x0
main.main()
/Users/meitu/test/go/map.go:16 +0x220
Goroutine 5 (running) created at:
main.main()
/Users/meitu/test/go/map.go:13 +0x1aa
==================
m1
和m2
是不同的变量,为什么第16行和第11行导致数据竞争?
我的版本是1.8。我想这是一些编译优化,有人可以告诉我它吗?非常感谢你。
答案 0 :(得分:3)
进行数据竞争的要求是:
在您的代码中,满足所有3个要求:
m1
,而您在其中启动的访问权限也会访问m1
。主goroutine在启动另一个goroutine之后访问它,因此它们是并发。m1
:m1 = m2
。因此,这是一场数据竞赛。
显而易见的数据竞争是在第11行读取m1
和第17行写m1
之间。
但是!由于第17行将m2
分配给m1
,然后当/如果启动的goroutine继续运行,它会尝试读取m1
现在可能值m2
的{{1}},因为我们已将m2
分配给m1
。这是什么意思? 这引入了另一个数据竞赛写作m2
和阅读m1
。
如果程序没有立即结束(可能,但不一定),那么就在#17行之后,那么启动的goroutine会尝试从最后写的m1
读取m2
在第16行,所以这解释了第11行和第16行之间的“冲突”。
完整的go run -race
输出如下:
==================
WARNING: DATA RACE
Write at 0x00c42000e010 by main goroutine:
main.main()
/home/icza/gows/src/play/play2.go:17 +0x22f
Previous read at 0x00c42000e010 by goroutine 5:
[failed to restore the stack]
Goroutine 5 (running) created at:
main.main()
/home/icza/gows/src/play/play2.go:9 +0x190
==================
==================
WARNING: DATA RACE
Read at 0x00c42007e000 by goroutine 5:
runtime.mapaccess1_faststr()
/usr/local/go/src/runtime/hashmap_fast.go:208 +0x0
main.main.func1()
/home/icza/gows/src/play/play2.go:11 +0x7a
Previous write at 0x00c42007e000 by main goroutine:
runtime.mapassign_faststr()
/usr/local/go/src/runtime/hashmap_fast.go:598 +0x0
main.main()
/home/icza/gows/src/play/play2.go:16 +0x1fc
Goroutine 5 (running) created at:
main.main()
/home/icza/gows/src/play/play2.go:9 +0x190
==================
==================
WARNING: DATA RACE
Read at 0x00c420080088 by goroutine 5:
main.main.func1()
/home/icza/gows/src/play/play2.go:11 +0x90
Previous write at 0x00c420080088 by main goroutine:
main.main()
/home/icza/gows/src/play/play2.go:16 +0x212
Goroutine 5 (running) created at:
main.main()
/home/icza/gows/src/play/play2.go:9 +0x190
==================
Found 3 data race(s)
exit status 66
答案 1 :(得分:0)
数据竞赛
当两个goroutine同时访问同一个变量并且至少有一个访问是写入时,就会发生数据争用。
说明重新排序
编译器和处理器可能会重新排序在单个goroutine中执行的读写操作,只要重新排序不会改变例程中的行为,它就不会“确保其他goroutine的行为不受影响”m2["hello"] = 3
m1 = m2
可以重新订购
m1 = m2
m2["hello"] = 3
这不会改变主程序的行为,因此比赛检查也会考虑评估竞争条件。现在我们有m2["hello"] = 3
导致竞争条件,并且打印出与原始行号相同的