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
and m2
是不同的变量,为什么第16行和第11行会导致数据竞争?
我的go版本是1.8。我想这是一些编译优化,有人可以告诉我吗?非常感谢。
The 要求进行数据竞赛是:
-
多个 goroutine访问相同的资源(例如变量)同时.
- 这些访问中至少有一个是write.
- 访问权限是不同步.
在您的代码中,满足了所有 3 个要求:
- 你有主 goroutine 访问
m1
,并且您在其中启动的那个也可以访问m1
。主 Goroutine 在其他 Goroutine 启动后访问它,所以它们是同时.
- 主goroutine写的是
m1
第 17 行:m1 = m2
.
- 访问不同步,您不使用互斥体或通道或类似的东西(睡眠是not同步)。
因此,这是一场数据竞赛。
明显的数据竞争发生在 #11 行之间m1
,以及第 17 行写作m1
.
但!由于第 17 行分配了m2
to m1
,那么当/如果启动的 goroutine 继续运行,它会尝试读取m1
which 现在可能是的价值m2
因为我们分配了m2
to 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)