Println在循环和闭包中输出不同的值

时间:2014-01-06 23:33:56

标签: go

我有以下代码:

dirs, err      := get_directories(bucket, start_dir, "")

其中dirs是一个字符串数组。在那之后,我正在循环它们:

for _, dir     := range dirs {
  fmt.Println("le dir",dir)
  go func() {
    fmt.Println("working on",dir)
    get_files(bucket, dir, "")
    wg.Done()
  }()
}

wg.Wait()

在dirs中,我有[“one”,“two”],如果我看到以下内容:

le dir one
le dir two
working on one
working on one

为什么gorouting没有使用dir的正确值?

1 个答案:

答案 0 :(得分:1)

您正在创建多个执行线程(goroutines),这些线程无法保证以任何特定顺序执行(这是并发的本质)。因此,理论上主线程可以在调度程序调度任何goroutine之前完成其循环。这可能就是你所经历的。

因为主循环在任何goroutine执行第一条指令之前已经完成执行,dir已经到达其最终值,所以每个goroutine都会使用它(值在创建闭包时dir。)

如果你循环次数更多(dirs中的元素更多)或者每次循环迭代需要花费更长的时间来执行(例如,如果你在循环中Wait()),你可能会开始看看你的主程序的印刷语句和你的goroutines的印刷语句之间的混合。

以下是对您的示例的简化,惯用的重写,对于可能会发现此问题有用的其他人:

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
}