【发布时间】:2021-04-15 04:20:18
【问题描述】:
关于 int 类型的 Go 数据竞争的问题。
当我通过go run -race main.go 运行下面的程序时,
package main
import "fmt"
var i int
func main() {
go func() {
i = 10
}()
i = 5
fmt.Println(i)
}
它显示数据竞争警告。
~ $ go run -race main.go
5
==================
WARNING: DATA RACE
Write at 0x000000605908 by goroutine 7:
main.main.func1()
/home/dty1er/main.go:80 +0x3a
Previous write at 0x000000605908 by main goroutine:
main.main()
/home/dty1er/main.go:83 +0x56
Goroutine 7 (running) created at:
main.main()
/home/dty1er/main.go:79 +0x46
==================
Found 1 data race(s)
exit status 66
我知道为什么会发生这种数据竞争; var i 被 2 个 goroutines 并发访问,没有任何同步。
我不明白的是这段代码的实际问题。据我了解,因为i 是int,(而我的电脑是64 位的),所以i 实际上是64 位的。在 64 位机器上,i 可以原子地读取/写入。所以我认为没有实际问题。
例如,如果类型是map或者slice,由于CPU的内存访问不能是原子的,所以它的中间状态有时是可见的,这是有问题的。
但是当我只是使用int类型值时,即使有数据竞争,看起来也没有实际问题。
我的理解正确吗?
【问题讨论】:
-
查看旧的What could possibly go wrong? 博文。
-
在 64 位机器上,i 可以被原子地读取/写入。 这太过简单了。您有多个内核、分支预测、编译器优化,并且可能最重要的是,该语言指定不允许这样做,仅举几个您无法以可靠结果执行此操作的原因。
-
您也不是在机器级别编写代码,而是为 Go 编译器和运行时编写代码。如果语言规范说它无效,那么硬件做什么都没关系。如果不需要额外的指令来在你的硬件上分配整数值(注意 Go 在许多不同的架构上运行),那么 编译器 如果可以这样做。
-
看看旧的 可能出了什么问题? blog-post 我应该早点读到这个。谢谢!
-
语言指定这是不允许的事实我在 Go 语言规范中找不到这是不允许的。这是各种语言的共同行为吗?
标签: go concurrency goroutine