Go 中的数据竞争:为什么它发生在 10-11 毫秒以下?
Data race in Go: Why does it happen below 10-11ms?
这是我的代码 运行:
package main
import (
"fmt"
"time"
)
const delay = 9 * time.Millisecond
func main() {
n := 0
go func() {
time.Sleep(delay)
n++
}()
fmt.Println(n)
}
这是我使用的命令:
go run -race data_race_demo.go
这是我注意到的行为:
- 将
delay
设置为 9 毫秒或更低时,始终会检测到数据争用(程序抛出 Found 1 data race(s)
)
- 将
delay
设置为 12 毫秒或更高时,永远不会检测到数据竞争(程序只是打印 0
)
- 将
delay
设置为 10 到 11 毫秒,间歇性地发生数据竞争(也就是说,有时打印 0
有时抛出 Found 1 data race(s)
)
为什么会发生这种情况 大约 10-11 毫秒?
如果重要的话,我在 darwin/amd64
上使用 Go 1.16.3。
您有 2 个 goroutine:main
和您启动的那个。他们在没有同步的情况下访问 n
变量(其中一个是写入):那是一场数据竞争。
是否检测到这种竞争取决于这种不正当访问是否发生。 ,它不会等待其他非 main
goroutines 完成。
如果增加睡眠延迟,main()
将比睡眠结束更早结束,并且不会等待 n++
异常写入发生,因此不会检测到任何内容。如果睡眠很短,比 fmt.Prinln()
执行时间短,则会发生并检测到异常写入。
10 毫秒没什么特别之处。这只是在 您的 环境中执行 fmt.Println()
和终止您的应用程序所需的大概时间。如果您在 Println()
语句之前执行其他“冗长”任务,例如:
for i := 0; i < 5_000_000_000; i++ {
}
fmt.Println(n)
即使有 50 毫秒的睡眠也会检测到竞争(因为该循环将需要一些时间来执行,允许在 n
读取 fmt.Println()
调用和应用终止)。 (一个简单的 time.Sleep()
也可以,我只是不想让任何人得出错误的结论,即他们以某种方式相互“互动”。)
这是我的代码 运行:
package main
import (
"fmt"
"time"
)
const delay = 9 * time.Millisecond
func main() {
n := 0
go func() {
time.Sleep(delay)
n++
}()
fmt.Println(n)
}
这是我使用的命令:
go run -race data_race_demo.go
这是我注意到的行为:
- 将
delay
设置为 9 毫秒或更低时,始终会检测到数据争用(程序抛出Found 1 data race(s)
) - 将
delay
设置为 12 毫秒或更高时,永远不会检测到数据竞争(程序只是打印0
) - 将
delay
设置为 10 到 11 毫秒,间歇性地发生数据竞争(也就是说,有时打印0
有时抛出Found 1 data race(s)
)
为什么会发生这种情况 大约 10-11 毫秒?
如果重要的话,我在 darwin/amd64
上使用 Go 1.16.3。
您有 2 个 goroutine:main
和您启动的那个。他们在没有同步的情况下访问 n
变量(其中一个是写入):那是一场数据竞争。
是否检测到这种竞争取决于这种不正当访问是否发生。 main
goroutines 完成。
如果增加睡眠延迟,main()
将比睡眠结束更早结束,并且不会等待 n++
异常写入发生,因此不会检测到任何内容。如果睡眠很短,比 fmt.Prinln()
执行时间短,则会发生并检测到异常写入。
10 毫秒没什么特别之处。这只是在 您的 环境中执行 fmt.Println()
和终止您的应用程序所需的大概时间。如果您在 Println()
语句之前执行其他“冗长”任务,例如:
for i := 0; i < 5_000_000_000; i++ {
}
fmt.Println(n)
即使有 50 毫秒的睡眠也会检测到竞争(因为该循环将需要一些时间来执行,允许在 n
读取 fmt.Println()
调用和应用终止)。 (一个简单的 time.Sleep()
也可以,我只是不想让任何人得出错误的结论,即他们以某种方式相互“互动”。)