Sobes.tech
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 i for all iterations. By the time the anonymous function executes, the value of i may 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:

  1. 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)
    }
}
  1. 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)
        }()
    }
}
  1. 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.