循环中的func闭包

时间:2014-07-05 11:51:30

标签: concurrency go closures

当执行以下代码时,我得到了第一个循环完成时的预期(从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

为什么第二个循环不打印序列?

1 个答案:

答案 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