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。我想这是一些编译优化,有人可以告诉我吗?非常感谢。
发布于 2017-09-15 07:15:51
requirements 进行数据竞争是:
在您的代码中,满足了所有3项要求:
m1的主goroutine,在其中开始的访问也访问m1。主goroutine在其他goroutine启动后访问它,因此它们是并行的。m1写在第17行:m1 = m2中。因此,这是一个数据竞赛。
显而易见的数据竞争是在读取m1的第11行和写m1的第17行之间。
但!由于第17行将m2分配给m1,那么当/如果已启动的goroutine继续运行时,它将尝试读取m1,这可能是m2的值,因为我们将m2分配给m1。这意味着什么?m2介绍了另一个数据竞赛--编写和mean m1**.**
这是在第17行之后,如果程序没有立即结束(它可能,但不一定),那么启动的goroutine尝试从m1 (现在是最后一次写在第16行中的m2 )读取,所以这解释了第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发布于 2017-09-15 07:40:31
数据竞争
当两个goroutines同时访问相同的变量并且至少一个访问是写时,就会发生数据竞争。
指令重新排序
编译器和处理器可以重新排序在单个goroutine中执行的读和写,只要重新排序不会改变例程中的行为,它将确保其他goroutines的行为不受影响。
m2["hello"] = 3
m1 = m2可以重新排序
m1 = m2
m2["hello"] = 3这不会改变主例程的行为,因此,竞赛检查也会考虑这一点,以评估比赛状况。现在我们有了引起竞赛条件的m2["hello"] = 3,它打印出了与其原始行号相同的结果。
https://stackoverflow.com/questions/46233680
复制相似问题