在循环中使用Go函数闭包

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

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

确定