3

这是我运行的代码:

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设置为 9ms 或更低,始终检测到数据竞争(程序抛出Found 1 data race(s)
  • 设置为 12ms 或更高,永远不会检测到delay数据竞争(程序简单地打印0
  • 设置为 10到delay11ms 时,数据竞争会间歇性发生(即有时会打印0,有时会抛出Found 1 data race(s)

为什么会在 10-11ms 左右发生这种情况?

如果这很重要,我正在使用 Go 1.16.3 darwin/amd64

4

1 回答 1

5

你有 2 个 goroutine:main和你启动的那个。他们在n没有同步的情况下访问变量(一个是写入):这是一场数据竞争。

是否检测到这种竞争取决于这种竞争性访问是否发生。main()函数结束时,您的应用程序也会结束,它不会等待其他非maingoroutine 完成。

如果增加睡眠延迟,main()它将比睡眠结束更早结束,并且不会等待n++激烈的写入发生,因此不会检测到任何内容。如果睡眠时间很短,比fmt.Prinln()执行时间短,那么会发生并检测到异常写入。

10ms 没有什么特别的这只是在您的环境中执行fmt.Println()和终止您的应用程序所需的大致时间。如果您在声明之前执行其他“冗长”任务,例如:Println()

for i := 0; i < 5_000_000_000; i++ {
}
fmt.Println(n)

即使在 50 毫秒睡眠时也会检测到比赛(因为该循环将需要一些时间来执行,从而允许在n读取fmt.Println()调用之前发生激烈的写入并且应用程序终止)。(一个简单的time.Sleep()也可以,我只是不想让任何人得出错误的结论,即他们以某种方式相互“互动”。)

于 2021-05-21T12:17:02.907 回答