鉴于下面的代码,我试图了解为什么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 Server在单独的goroutine中响应所有请求。考虑到这一点,处理程序函数对全局计数变量的增量不会发生在与主goroutine分开的goroutine中,从而构成数据竞争吗?
如果这不是数据竞赛,我非常想知道原因。
答案 0 :(得分:4)
这是一场数据竞赛,但是比赛探测器并没有报告未发生的比赛。您需要确保测试中有并发调用,并确保GOMAXPROCS>1
也可以帮助清除它们。
答案 1 :(得分:4)
那是一场竞争条件。 False negatives can happen with the race checker.
竞赛检查器是动态的:不是检查源是否有问题,它只能查看读取和写入是否实际发生而两者之间没有同步操作。您的代码中没有同步操作,但如果在net/http
之间出现增量,则会被欺骗。基本上,Its author suggests运行并发压力测试以解决问题:
- 写好并发测试
- 使用竞赛检测器持续构建
- 运行集成测试
- 在生产中运行支持种族的金丝雀
在Go 1.4及更低版本中,您还应确保您的程序在多个核心上运行,例如runtime.GOMAXPROCS(runtime.NumCPU())
。在Go 1.5中,将于2015年底发布,GOMAXPROCS默认会在所有可用内核上运行您的代码。
答案 2 :(得分:3)
count++
是一场数据竞赛。它不是原子地发生的。它与:
count = count + 1
如果竞赛检测器没有看到它,你可能没有足够地击中服务器。