问题
最近在代码中遇到了这么一个问题,现在有一个循环,每一个循环中创建一个协程用来执行函数,我发现函数运行的结果却是大部分时候都是使用最后一个循环变量,不符合实际要求。
大概的代码如下:
package main
import (
"fmt"
"net/http"
)
func main() {
for i := 0; i < 10; i++ {
go func() { fmt.Println(i) }()
}
http.ListenAndServe(":8080", nil)
}
运行:
10
10
10
10
10
10
10
10
10
10
多次运行,可以发现大部分情况都是将 i = 10 代入函数执行。
原因
那这是为什么呢? 这个就是函数闭包。协程运行的是一个闭包函数,其中使用了主线程的变量i 。看上去这和第一组几乎一样。但是在每个协程中,从进入匿名函数到调用Println将i的值复制入栈之间仍需要一小段时间运行,而这段时间内足以主线程完成全部10次循环。所以终于到将i的值复制入栈调用Println时,i已经成为10且不再变化了。
解决
那该怎么解决使代码如我们的需求运行呢?
我们只需将变量 i 复制进栈中即可,改动后的代码:
package main
import (
"fmt"
"net/http"
)
func main() {
for i := 0; i < 10; i++ {
go func(j int) { fmt.Println(j) }(i)
}
http.ListenAndServe(":8080", nil)
}
结果:
0
4
1
2
3
6
5
7
8
9