2

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?

Kiril
  • 6,009
  • 13
  • 57
  • 77
  • Read the documentation: [What happens with closures running as goroutines?](http://golang.org/doc/faq#closures_and_goroutines) – peterSO Jul 05 '14 at 12:35
  • Thanks. Was looking in 'Effective Go' but didn't find anything. So, the FAQs hold the answer. – Kiril Jul 05 '14 at 12:45

1 Answers1

5

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.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138