【问题标题】:Data race in Go: Why does it happen below 10-11ms?Go 中的数据竞赛:为什么会发生在 10-11 毫秒以下?
【发布时间】:2021-05-21 12:14:46
【问题描述】:

这是我运行的代码:

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,如果这很重要的话。

【问题讨论】:

  • “延迟设置为 12 毫秒或更高,永远不会检测到数据竞争”这意味着什么:竞争仍然存在。

标签: go data-race


【解决方案1】:

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

是否检测到这种竞争取决于这种竞争性访问是否发生。 When the main() function ends, your app ends as well,它不会等待其他非main goroutines 完成。

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

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

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

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

【讨论】:

  • 谢谢。但是,10ms 有什么特别之处呢?
  • @ManuManjunath 大约 10 毫秒没有什么特别的。这只是在 your 环境中执行 fmt.Println() 并终止您的应用程序所需的时间。
  • fmt.Println 之前你甚至不需要做任何事情,只要让 goroutine 在退出前运行就会显示比赛,即使你在读取和写入之间等待了几秒钟。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
  • 1970-01-01
  • 2014-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多