这是“Race on counter loop”的经典例子。如果你运行你的代码,go run -race
我怀疑它会告诉你。
以下将满足您的期望:
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
}
您的原始代码可能在任何机器上只打印 b(或只 a),实际上它发生在 Go 操场上:http ://play.golang.org/p/Orgn030Yfr
这是因为匿名函数引用的是行中的变量for k, v
,而不是这些变量在创建 goroutine 时碰巧具有的值。首先将两个变量设置为一个值,并生成一个 goroutine,然后将它们设置为另一个值,并生成另一个 goroutine。然后,两个 goroutine 都运行了,它们都看到了 k 和 v 的最新值。顺便说一下,这并不是多线程或 Go 所特有的(play.golang.org 在一个线程中运行所有东西,并且仍然显示这个“错误。”)同样的问题发生在 JavaScript 中,保证只有一个线程:
obj = {a: 'a', b: 'b'};
for (k in obj) {
setTimeout(function() { console.log(k, obj[k]); }, 0);
}
http://goo.gl/vwrMQ -- 在匿名函数运行时,for 循环已经完成,所以对于函数的两次运行,'k' 都保留了它的最新值。