为什么局部变量是goroutine中匿名函数的不同参数

han*_*kim 2 go goroutine

package main

import (
  "fmt"
  "runtime"
)

func main() {
  runtime.GOMAXPROCS(runtime.NumCPU())
  fmt.Println(runtime.GOMAXPROCS(0))

  // s := "hello world \n"

  for i := 0; i < 100; i++ {
    go func(n int) {
        fmt.Println(n, i)
    }(i)
  }

  fmt.Scanln()
}
Run Code Online (Sandbox Code Playgroud)

我只是想知道为什么n不等于i每一个例程.

i有时具有相同的值在上一次调用.

这段代码有什么问题?

Sim*_*ead 5

这个主题很好地涵盖了(跨多种语言) - 但简短的版本是这样的:

您当前的输出是这样的:

1 100
2 100
3 100
4 100
...
Run Code Online (Sandbox Code Playgroud)

变量i成为闭包的一部分.这意味着它的值实际上超出了它的范围(它移到了一边,以便当goroutine执行时它知道在哪里找到i).

当调度程序开始执行你的goroutine时,for循环已经完成并且值i将为100(或者如果你在慢速机器上运行则接近它).

修复是每次迭代存储值并使用:

for i := 0; i < 100; i++ {
    x := i            // <------ Store the value of i each loop iteration
    go func(n int) {
        fmt.Println(n, x) // <---- Use the new, local, closed over value, not the main closed over one
    }(i)
} 
Run Code Online (Sandbox Code Playgroud)

现在每个goroutine引用它自己的一个闭合变量的副本x,你的输出变为:

1 1
2 2
3 3
4 4
...
Run Code Online (Sandbox Code Playgroud)

这种现象并不孤立于Go.

你可以在操场上看到一个工作样本: View it on the Playground