A Go Gotcha: When Closures and Goroutines Collide
Here's a small Go gotcha that it's easy to fall into when using goroutines and closures. Here's a simple program that prints out the numbers 0 to 9:
(You can play with this in the Go Playground here)
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
fmt.Printf("%d ", i)
}
}
It's output is easy to predict:
0 1 2 3 4 5 6 7 8 9
If you decided that it would be nice to run those fmt.Printf
s concurrently using goroutines you might be surprised by the result. Here's a version of the code that runs each fmt.Printf
in its own goroutine and uses a sync.WaitGroup
to wait for the goroutines to terminate.
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
fmt.Printf("%d ", i)
wg.Done()
}()
}
wg.Wait()
}
(This code is in the Go Playground here). If you're thinking concurrently then you'll likely predict that the output will be the numbers 0 to 9 in some Continue reading