Go HTTP 处理程序中的简单竞争条件 - 这真的是竞争条件吗?

Simple Race Condition in Go HTTP Handler - Is this really a race condition?

给出下面的代码,我试图理解为什么 Go 竞态检测器 (go run -race example.go) 不会抱怨竞态条件。

var count int

func main() {
    http.HandleFunc("/a/", func(w http.ResponseWriter, r *http.Request) {
        count++ 
        fmt.Println(count)
    })

    http.HandleFunc("/b/", func(w http.ResponseWriter, r *http.Request) {
        count++
        fmt.Println(count)
    })

    log.Fatal(http.ListenAndServe(":8080", nil))
}

据我了解,Go HTTP 服务器在单独的 goroutine 中响应所有请求。考虑到这一点,处理函数对全局计数变量的增量是否会发生在与主 goroutine 分开的 goroutine 中,从而构成数据竞争?

如果这不是数据竞赛,我很想知道为什么。

count++ 是一场数据竞赛。它不会自动发生。等同于:

count = count + 1

如果竞争检测器没有发现它,您可能没有足够努力地攻击服务器。

这是一场数据竞赛,但竞赛检测器不会报告未发生的竞赛。您需要确保测试中存在并发调用,确保 GOMAXPROCS>1 也有助于清除它们。

这是一个竞争条件。 False negatives can happen with the race checker.

竞争检查器是动态的:它不会检查源是否有问题,它只能查看读取和写入是否实际发生,中间没有同步操作。您的代码中没有同步操作,但如果在增量之间的 net/http 中出现同步操作,它将被愚弄。 Its author suggests,本质上,运行宁并发压力测试以解决问题:

  • write good concurrent tests
  • have continuous build with race detector
  • run integration tests
  • run race-enabled canaries in production

在 Go 1.4 及以下版本中,您还应确保您的程序 运行 位于多个内核上,例如 runtime.GOMAXPROCS(runtime.NumCPU())。在 2015 年底左右发布的 Go 1.5 中,GOMAXPROCS 将默认 运行 所有可用内核上的代码。