英文:
Go func closure in loop
问题
执行上述代码时,第一个循环完成后(从0到9的序列),得到了预期的结果。但是当第二个循环完成时,结果不符合预期(我期望的结果与第一个循环相同,但只打印出了'10')。
为什么第二个循环没有按序打印输出?
英文:
When executing the following code I get what I expect when the first loop is done (sequence from 0 to 9). But when the second loop finishes, the result is not what I expected (I expected the same result as in the first loop, but it prints only '10's):
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")
}
Output:
0
1
2
3
4
5
6
7
8
9
done first
10
10
10
10
10
10
10
10
10
10
done second
Why doesn't the second loop print a sequence?
答案1
得分: 5
因为第一个函数在每次迭代时都会获得循环计数器的副本,而第二个函数则将变量作为闭包的一部分进行捕获。
在第一个函数中,你在每次循环迭代中都将其传递进来:
go func(j int) {
defer wg.Done()
fmt.Println(j)
}(i) // <------------ 它在每次循环迭代中作为参数传递进来
而第二个函数则不接收任何参数...所以,循环计数器 i
被作为闭包的一部分进行捕获。当第一个 goroutine 执行时,for
循环已经结束。循环结束时,将 i
变量(现在作为闭包的一部分)设置为 10。第一个 goroutine 执行并打印出 i
的值...此时 i
的值已经是 10,其余的 goroutine 也是如此。
简而言之:问题在于在任何 goroutine 被调度运行之前,循环已经结束了——速度非常快。因此,当 goroutine 运行时,i == 10
。
英文:
Because the first one gets a copy of the loop counter each time. Whereas the second gets the variable captured as part of a closure.
In the first, you're passing it in here in every iteration of the loop:
go func(j int) {
defer wg.Done()
fmt.Println(j)
}(i) // <------------ its passed in here as part of each loop iteration
The second one receives nothing.. so, the loop counter i
is captured as part of a closure. By the time the first go routine executes, the for
loop has finished. The loop finishing has set the i
variable (that is now part of a closure) to 10. Go routine #1 executes and prints the value of i
.. which is now already 10 and the rest follow suit.
TLDR: The problem here is that the loop is finishing before any go routines are scheduled to be run - its just that quick. Therefore, i == 10
when the go routines run.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论