为什么会这样:
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?
为什么会这样:
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?
虽然 goroutine 很便宜,但它们并不是免费的。创建它们有一些但很少的开销。
在您的第一个程序中, 的值i
被保留到 goroutine 中,因为您将它作为参数传递。(此时,每个 goroutine 都有自己的i
' 值副本。)
在您的第二个程序中,i
在第一个 goroutine 开始之前, 的值已经是 3。请记住,Go 程序中的 goroutine 共享相同的内存空间,因此在这种情况下,每个 goroutine 在i
打印出来时都是相同的。
在你的循环之后添加一个打印语句for
应该会让你清楚。你会看到 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