Iteration variables and closures

yourbasic.org/golang

Why does this program

func main() {	var wg sync.WaitGroup	wg.Add(5)	for i := 0; i < 5; i++ {	go func() {	fmt.Print(i)	wg.Done()	}()	}	wg.Wait()	fmt.Println() }

print

55555 

(A WaitGroup waits for a collection of goroutines to finish.)

Answer

There is a data race: the variable i is shared by six (6) goroutines.

A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write.

To avoid this, use a local variable and pass the number as a parameter when starting the goroutine.

func main() {	var wg sync.WaitGroup	wg.Add(5)	for i := 0; i < 5; i++ {	go func(n int) { // Use a local variable.	fmt.Print(n)	wg.Done()	}(i)	}	wg.Wait()	fmt.Println() }

Example output:

40123 

It’s also possible to avoid this data race while still using a closure, but then we must take care to use a unique variable for each goroutine.

func main() {	var wg sync.WaitGroup	wg.Add(5)	for i := 0; i < 5; i++ {	n := i // Create a unique variable for each closure.	go func() {	fmt.Print(n)	wg.Done()	}()	}	wg.Wait()	fmt.Println() }

See Data races for a detailed explanation of data races in Go.