当执行以下代码时,我得到了第一个循环完成时的预期(从0到9的顺序)。但是当第二个循环结束时,结果不符合我的预期(我预期结果与第一个循环相同,但它只打印' 10')
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(j int) {
defer wg.Done()
fmt.Println(j)
}(i)
}
wg.Wait()
fmt.Println("done first")
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println(i)
}()
}
wg.Wait()
fmt.Println("done second")
}
输出:
0
1
2
3
4
5
6
7
8
9
done first
10
10
10
10
10
10
10
10
10
10
done second
为什么第二个循环不打印序列?
答案 0 :(得分:3)
因为第一个每次都获得一个循环计数器的副本。而第二个将变量作为闭包的一部分捕获。
在第一个中,你将在循环的每次迭代中传递它:
go func(j int) {
defer wg.Done()
fmt.Println(j)
}(i) // <------------ its passed in here as part of each loop iteration
第二个没有收到任何东西..所以,循环计数器i
被捕获作为闭包的一部分。到第一个例程执行时,for
循环已完成。循环完成将i
变量(现在是闭包的一部分)设置为10.执行例程#1并打印i
的值...现在已经是10,其余的跟随服。
TLDR:这里的问题是循环在任何计划运行的例程之前完成 - 就这么快。因此,当go例程运行时i == 10
。