问题
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:
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.
来源:https://stackoverflow.com/questions/24586141/go-func-closure-in-loop