考虑以下Golang代码(也在Go Playground上):
package main
import "fmt"
import "time"
func main() {
for _, s := range []string{"foo", "bar"} {
x := s
func() {
fmt.Printf("s: %s\n", s)
fmt.Printf("x: %s\n", x)
}()
}
fmt.Println()
for _, s := range []string{"foo", "bar"} {
x := s
go func() {
fmt.Printf("s: %s\n", s)
fmt.Printf("x: %s\n", x)
}()
}
time.Sleep(time.Second)
}
Run Code Online (Sandbox Code Playgroud)
此代码生成以下输出:
s: foo
x: foo
s: bar
x: bar
s: bar
x: foo
s: bar
x: bar
Run Code Online (Sandbox Code Playgroud)
假设这不是一些奇怪的编译器错误,我很好奇为什么a)s的值在goroutine版本中然后在常规func调用中被解释不同而b)以及为什么将它分配给循环内部的局部变量两种情况.
我已经找到了一种方法让代码按照我的意愿运行,但我想了解为什么它的行为如此,以便我对Go并发性的理解得到改善.
我正在测试sync.WaitGroup等待一些goroutines完成,因为我计划以这种方式多次上传到Amazon S3.
这是我原来的代码:
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go func() {
fmt.Println(i)
time.Sleep(time.Second * 1)
wg.Done()
}()
}
wg.Wait()
}
Run Code Online (Sandbox Code Playgroud)
我惊讶地看到输出是:6, 6, 6, 6, 6.
而不是像:2, 4, 1, 5, 3.
由于循环甚至没有达到6,这对我来说没有任何意义.我后来将i变量作为参数传递给匿名函数,然后它表现得像我预期的那样.
为什么会这样?我不明白.