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

huangapple go评论145阅读模式
英文:

Println in loop and closure output different values

问题

我有以下代码:

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

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

英文:

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?

答案1

得分: 1

你正在创建多个执行线程(goroutine),这些线程没有保证按照特定的顺序执行(这是并发的特性)。因此,理论上主线程在调度任何goroutine之前可能会完成其循环。这可能是你所经历的情况。

由于主循环在任何goroutine执行其第一条指令之前已经执行完毕,所以dir已经达到了最终值,因此每个goroutine都将使用该值(而不是创建闭包时的dir的值)。

如果你循环次数更多(dirs中有更多元素),或者每次循环执行时间更长(例如,在循环中使用Wait()),你可能会开始看到主程序和goroutine的打印语句交错出现。

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

package main

import "fmt"

func main() {
    ch1 := make(chan bool)

    // 使用1000次迭代,你可能会看到一些主线程和goroutine的打印语句交错出现
    for i := 0; i < 1000; i++ {
        fmt.Println("在启动goroutine之前:", i)
        go func() {
            fmt.Println("在goroutine中:", i)
            ch1 <- true // 发送信号表示“完成”
        }()
        // 或者,在这里添加`time.Wait()`(并减少循环迭代次数)以查看由于不同原因的交错。
    }

    <-ch1 // 等待goroutine完成
}

你可以在这里查看重写后的代码:http://play.golang.org/p/6G_8xOi9Fi

英文:

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 &quot;fmt&quot;

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&lt;1000;i++ {
		fmt.Println(&quot;before kicking off goroutine:&quot;, i)
		go func() {
			fmt.Println(&quot;in goroutine:&quot;, i)
			ch1 &lt;- true // signal &#39;done&#39;
		}()
        // alternatively, add a `time.Wait()` here
        // (and reduce the loop iterations) to see
        // intermingling for a different reason.
	}

	&lt;- ch1 // wait for goroutines to complete
}

huangapple
  • 本文由 发表于 2014年1月7日 07:33:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/20961302.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定