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

Bro*_*bay 4 go 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))
}
Run Code Online (Sandbox Code Playgroud)

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

如果这不是数据竞赛,我非常想知道原因。

Jim*_*imB 5

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


two*_*two 5

这是一个竞争条件。种族检查器可能会出现误报。

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

  • 编写良好的并发测试
  • 使用竞赛检测器进行连续构建
  • 运行集成测试
  • 在生产环境中运行支持竞赛的金丝雀

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