I have the following code:
dirs, err := get_directories(bucket, start_dir, "")
Where dirs is an array of strings. After that, I'm looping over them:
for _, dir := range dirs {
fmt.Println("le dir",dir)
go func() {
fmt.Println("working on",dir)
get_files(bucket, dir, "")
wg.Done()
}()
}
wg.Wait()
In dirs, I have ["one", "two"], and if I see the following content:
le dir one
le dir two
working on one
working on one
Why is the gorouting not using the correct value of dir
?
You're creating multiple threads of execution (goroutines), which aren't guaranteed to execute in any particular order (this is the nature of concurrency). Because of this, it's theoretically possible for the main thread to finish its loop before the scheduler dispatches any of the goroutines. This is probably what you're experiencing.
Because the main loop has finished executing before any of the goroutines executes its first instruction, dir
has arrived at its final value, and so each goroutine will use that (not the value of dir
when the closure was created).
If you looped more times (more elements in dirs
) or if each loop iteration took a lot longer to execute (for example, if you Wait()
ed in your loop), you would probably start to see some intermingling between the print statements of your main routine and those of your goroutines.
Here is a simplified, idiomatic rewrite of your example, for others who might find this question useful:
http://play.golang.org/p/6G_8xOi9Fi
package main
import "fmt"
func main() {
ch1 := make(chan bool)
// with 1000 iterations, you can probably see some intermingling
// between lines printed via goroutines and those of your main thread
for i:=0;i<1000;i++ {
fmt.Println("before kicking off goroutine:", i)
go func() {
fmt.Println("in goroutine:", i)
ch1 <- true // signal 'done'
}()
// alternatively, add a `time.Wait()` here
// (and reduce the loop iterations) to see
// intermingling for a different reason.
}
<- ch1 // wait for goroutines to complete
}