英文:
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 "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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论