gpt4 book ai didi

go - 为什么这段代码会导致数据竞争?

转载 作者:IT王子 更新时间:2023-10-29 01:38:32 24 4
gpt4 key购买 nike

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
==================

m1m2是不同的变量,为什么第16行和第11行会导致data race?

我的go版本是1.8。我想这是一些编译优化,有人可以告诉我吗?非常感谢。

最佳答案

进行数据竞争的要求是:

  1. 多个 goroutines并发访问同一资源(例如变量)。
  2. 这些访问中至少有一个是
  3. 访问未同步

在您的代码中满足所有 3 个要求:

  1. 您的主 goroutine 访问 m1,您在其中启动的 goroutine 也访问 m1。主 goroutine 在另一个 goroutine 启动后访问它,因此它们是并发
  2. 主 goroutine 在第 17 行写入 m1:m1 = m2
  3. 访问不同步,您不使用互斥体或 channel 或类似的东西( sleep 不是同步)。

因此这是一场数据竞赛。

明显的数据竞争发生在第 11 行读取 m1 和第 17 行写入 m1 之间。

但是!由于第 17 行将 m2 分配给 m1,然后当/如果启动的 goroutine 继续运行,它会尝试读取 m1 现在可能是m2 的值,因为我们将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

关于go - 为什么这段代码会导致数据竞争?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46233680/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com