Go

How does the race detector work, and what are its limitations? Is a "benign" data race ever OK?

Question 234MediumGo 1.22 to 1.25

-race (for go test, go run and go build) instruments every memory access and synchronization operation. It uses ThreadSanitizer's happens-before algorithm, based on vector clocks. When two accesses to the same address come from different goroutines, at least one is a write, and there is no happens-before edge between them, it prints both stacks.

Limitations:

  • It finds only races that actually happen during the run, with no false positives. Coverage depends on your tests exercising the concurrent paths, so run with -count and realistic parallelism.
  • It costs roughly 2-20x CPU and 5-10x memory, so it is used in CI and canaries, not across a production fleet.
  • It only runs on supported OS and architecture combinations (linux, darwin, windows and freebsd on amd64/arm64, among a few others). On most platforms, Linux and Windows included, it needs cgo and a C toolchain; macOS has not needed cgo for it since Go 1.20.

No race is benign in Go.

  • Interfaces and slices are multiword, so a racy read can see a type pointer from one write and a data pointer from another. That can segfault or corrupt memory.
  • A race on a map triggers fatal error: concurrent map writes. This fatal error cannot be recovered.
  • The compiler is free to optimize under the assumption that the program is race-free.
go test -race -count=5 ./...

What the interviewer is looking for: -race in CI, plus the understanding that a clean -race run is not proof that the code is race-free.

More on Concurrency Patterns & sync

All 38 Concurrency Patterns & sync questions