我正在学习Go,并试图了解其并发功能。
我有以下程序。
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
x := i
go func() {
defer wg.Done()
fmt.Println(x)
}()
}
wg.Wait()
fmt.Println("Done")
}
执行后,我得到:
4
0
1
3
2
这就是我想要的。但是,如果我对其进行一些修改:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println(i)
}()
}
wg.Wait()
fmt.Println("Done")
}
我得到的将是:
5
5
5
5
5
我不太了解两者之间的区别。谁能帮助解释这里发生的事情以及Go运行时如何执行此代码?
最佳答案
每次运行x := i
时,您都有一个新变量,
通过在goroutine中打印x
的地址,此代码很好地显示了差异:
The Go Playground:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
x := i
go func() {
defer wg.Done()
fmt.Println(&x)
}()
}
wg.Wait()
fmt.Println("Done")
}
输出:
0xc0420301e0
0xc042030200
0xc0420301e8
0xc0420301f0
0xc0420301f8
Done
并使用
go build -race
构建第二个示例并运行它:您将看到:
WARNING: DATA RACE
这会很好The Go Playground:
//go build -race
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println(i)
}(i)
}
wg.Wait()
fmt.Println("Done")
}
输出:
0
4
1
2
3
Done
关于multithreading - Golang如何在goroutine之间共享变量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39207608/