This is a classic example of a "Race on counter loop". If you run your code with go run -race
I suspect it will tell you that.
The following will do what you expect:
func main() {
completed := make(chan bool, 2)
m := map[string]string{"a": "a", "b": "b"}
for k, v := range m {
go func(k, v string) {
fmt.Println(k, v)
completed <- true
}(k, v)
}
<- completed
<- completed
}
Your original code is likely to print only b's (or only a's), on any machine, and in fact it happens on the Go playground: http://play.golang.org/p/Orgn030Yfr
This is because the anonymous function is referring to the variables from the for k, v
line, not the values that those variables happen to have at the moment the goroutine is created. First both variables are set to one value, and one goroutine is spawned, then they're set to the other value, and another goroutine is spawned. Then, both goroutines run, and they both see the newest values of k and v. By the way, this isn't really specific to multithreading or to Go (play.golang.org runs everything in a single thread and still shows this "bug.") This same problem happens in JavaScript where there is guaranteed to be only one thread:
obj = {a: 'a', b: 'b'};
for (k in obj) {
setTimeout(function() { console.log(k, obj[k]); }, 0);
}
http://goo.gl/vwrMQ -- by the time the anonymous function runs, the for loop has finished, so 'k' is left with its most recent value for both runs of the function.