为什么这样:
for i := 0; i < 3; i++ {
go func(i int) {
fmt.Printf("%d", i)
}(i)
}
打印012
虽然:
for i := 0; i < 3; i++ {
go func() {
fmt.Printf("%d", i)
}()
}
打印333?
答案 0 :(得分:3)
虽然goroutines便宜,但它们不是免费的。创建它们有一些但很少的开销。
在你的第一个程序中,i
的值保留在goroutines中,因为你将它作为参数传递。 (此时每个goroutine都会获得自己i
值的副本。)
在第二个程序中,i
的值在第一个goroutine开始之前已经是3。请记住,goroutine在Go程序中共享相同的内存空间,因此在这种情况下,每个goroutine在打印出来时都会查看相同的i
。
答案 1 :(得分:2)
在for
循环之后添加一个print语句应该会让你明白。您将看到该print语句在您的goroutine函数之前运行。
如果你在for
循环中所做的只是启动一个新的goroutine,你的循环通过非常快,通常在你的第一个goroutine开始之前完成。因此,当您的goroutine开始循环时,您的循环已经完成,if i
的值为3
。记住这一点。
当您将i
作为函数参数传递时,就像在第一个示例中那样,它的当前值是复制到函数堆栈,因此函数接收其当前值为一个论点。这就是为什么你会看到012
。但是当一个闭包函数只是在它的周围范围内使用一个变量时,就像你在第二个例子中那样,它在运行时访问它的当前值,在你的情况下是在循环结束并且i
已经到达之后3
。
您可以使用以下代码查看此效果:
for i := 0; i < 3; i++ {
go func(arg int) {
fmt.Printf("%d %d\n", arg, i)
}(i)
}
产生这个输出:
0 3
1 3
2 3