Go⚡Concurrencyintermediate
The Race Detector
Go · Concurrency · Run with go run
Explanation
A data race occurs when two goroutines access the same memory concurrently and at least one writes, with no synchronization. Go ships a built-in race detector enabled with the `-race` flag (`go run -race`, `go test -race`, `go build -race`). It instruments memory accesses and reports the conflicting goroutines, stacks, and addresses at runtime.
Real-World Scenario
A test passes locally but fails intermittently in CI. Running the test suite with `go test -race ./...` reveals that two goroutines mutate a shared map without a mutex — the detector pinpoints the exact lines, turning a heisenbug into a one-line fix (`sync.Mutex` or a channel).
Quick Snippet
snippet.go
// This code has a data race — run with: go run -race race_detector.go
var counter int
func main() {
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter++ // RACE: unsynchronized write
}()
}
wg.Wait()
}
// The fix: protect counter with sync.Mutex or use atomic.Int64.
// Always run tests with -race in CI to catch races early.Full Example
race_detector.go
// Compile: go run race_detector.go
// Detect races: go run -race race_detector.go
// Output:
// final count: 100
//
// The racy version is shown in raceyIncrement (commented call). The
// synchronized version below uses atomic.Int64 and is race-free — the
// race detector (-race) reports nothing for it.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
// raceyIncrement has a data race: 100 goroutines write `counter`
// with no synchronization. `go run -race` flags it.
func raceyIncrement() {
var counter int
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() { defer wg.Done(); counter++ }() // RACE
}
wg.Wait()
_ = counter
}
// safeIncrement is the fix: atomic operations are race-free.
func safeIncrement() int64 {
var counter atomic.Int64
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() { defer wg.Done(); counter.Add(1) }()
}
wg.Wait()
return counter.Load()
}
func main() {
// raceyIncrement() // uncomment and run with -race to see the report
fmt.Println("final count:", safeIncrement())
}
Run command
go run race_detector.go