Junior — Senior
Data race problem when launching goroutines in a loop
livecode
Task condition
This example shows a typical mistake when multiple goroutines use the loop variable simultaneously. What specific bug is present in the code and what methods can be used to eliminate it?
func main(){
for i := 0; i < 10; i++ {
go func(){
fmt.Println(i)
}()
}
}
What happens:
- The loop uses the same variable
ifor all iterations. By the time the anonymous function executes, the value ofimay have changed, so goroutines might print the same or skipped numbers. - Additionally, the loop header uses a colon instead of a semicolon, which makes the code syntactically incorrect.
How to fix:
- Pass the current index as a parameter to the function. This creates a separate copy of the value for each goroutine.
func main() {
for idx := 0; idx < 10; idx++ {
go func(v int) {
fmt.Println(v)
}(idx)
}
}
- Use a local variable inside the loop body.
func main() {
for i := 0; i < 10; i++ {
v := i // separate copy
go func() {
fmt.Println(v)
}()
}
}
- Synchronize goroutine completion, for example, using
sync.WaitGroup, to ensure all numbers are printed before the program exits.
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(v int) {
defer wg.Done()
fmt.Println(v)
}(i)
}
wg.Wait()
}
These techniques eliminate race conditions and make the program predictable.