The race, and the fix in Go
An unguarded increment loses updates; the race detector finds it.
// racy increments the same int from many goroutines: run with -race.
func racy(times int) int {
count := 0
var wg sync.WaitGroup
for range times {
wg.Go(func() { count++ })
}
wg.Wait()
return count
}
func safe(times int) int64 {
var count atomic.Int64
var wg sync.WaitGroup
for range times {
wg.Go(func() { count.Add(1) })
}
wg.Wait()
return count.Load()
}
How it works
count++is a read, an add and a write.- Run the tests with -race to have the runtime catch it.
- The fix is a mutex or an atomic, not hope.
Keywords and builtins used here
forfuncintint64rangereturnvar
The run, in numbers
- Lines
- 20
- Characters to type
- 358
- Tokens
- 93
- Three-star pace
- 95 tpm
At the three-star pace of 95 tokens a minute, this run takes about 59 seconds.
Step 3 of 3 in Goroutines, step 3 of 25 in Concurrency.