在循环中使用Go函数闭包

huangapple go评论127阅读模式
英文:

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):

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. func main() {
  7. var wg sync.WaitGroup
  8. for i := 0; i < 10; i++ {
  9. wg.Add(1)
  10. go func(j int) {
  11. defer wg.Done()
  12. fmt.Println(j)
  13. }(i)
  14. }
  15. wg.Wait()
  16. fmt.Println("done first")
  17. for i := 0; i < 10; i++ {
  18. wg.Add(1)
  19. go func() {
  20. defer wg.Done()
  21. fmt.Println(i)
  22. }()
  23. }
  24. wg.Wait()
  25. fmt.Println("done second")
  26. }

Output:

  1. 0
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. 6
  8. 7
  9. 8
  10. 9
  11. done first
  12. 10
  13. 10
  14. 10
  15. 10
  16. 10
  17. 10
  18. 10
  19. 10
  20. 10
  21. 10
  22. done second

Why doesn't the second loop print a sequence?

答案1

得分: 5

因为第一个函数在每次迭代时都会获得循环计数器的副本,而第二个函数则将变量作为闭包的一部分进行捕获。

在第一个函数中,你在每次循环迭代中都将其传递进来:

  1. go func(j int) {
  2. defer wg.Done()
  3. fmt.Println(j)
  4. }(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:

  1. go func(j int) {
  2. defer wg.Done()
  3. fmt.Println(j)
  4. }(i) // &lt;------------ 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.

huangapple
  • 本文由 发表于 2014年7月5日 19:51:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/24586141.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定