我有与goroutines的循环。我在循环中创建了go例程,它打印了一个字符串,“i”是一个int。我知道字符串和“i”将以随机顺序打印。但是“i”没有正确添加,如下所示。对于五个字符串中的三个或四个,该值保持不变,然后跳转到2或1.不应该以随机顺序存在1,2,3,4,5?我做错了什么?
package main
import (
"fmt"
"sync"
)
func main() {
a := []string{
"apple",
"orange",
"grape",
"peach",
"lemon",
}
wg := sync.WaitGroup{}
wg.Add(len(a))
i := 0
for _, v := range a {
go func(a string) {
fmt.Println(a, i)
i++
wg.Done()
}(v)
}
wg.Wait()
}
结果1:
orange 0
apple 0
lemon 0
peach 2
grape 0
结果2:
lemon 0
grape 0
peach 0
apple 0
orange 1
我的目标(随机顺序)
lemon 2
grape 4
peach 1
apple 0
orange 3
答案 0 :(得分:6)
通过闭包,所有goroutine共享相同的变量i
。试试这个:
package main
import (
"fmt"
"sync"
)
func main() {
a := []string{
"apple",
"orange",
"grape",
"peach",
"lemon",
}
wg := sync.WaitGroup{}
wg.Add(len(a))
for i, v := range a {
go func(a string, j int) {
fmt.Println(a, j)
wg.Done()
}(v,j)
}
wg.Wait()
}
通常:在您发布的程序中,您正在阅读i
并从不同的goroutine编写i
而没有任何同步。这是一场数据竞赛。在那种情况下可能发生任何事情。
go race detector甚至会对你大喊大叫
go run -race test.go
apple 0
==================
WARNING: DATA RACE
Read at 0x00c420010268 by goroutine 7:
main.main.func1()
/home/erwo/test.go:22 +0x6d
Previous write at 0x00c420010268 by goroutine 6:
main.main.func1()
/home/erwo/test.go:23 +0x191
Goroutine 7 (running) created at:
main.main()
/home/erwo/test.go:25 +0x15f
Goroutine 6 (finished) created at:
main.main()
/home/erwo/test.go:25 +0x15f
==================
orange 1
==================
WARNING: DATA RACE
Read at 0x00c420010268 by goroutine 8:
main.main.func1()
/home/erwo/test.go:22 +0x6d
Previous write at 0x00c420010268 by goroutine 6:
main.main.func1()
/home/erwo/test.go:23 +0x191
Goroutine 8 (running) created at:
main.main()
/home/erwo/test.go:25 +0x15f
Goroutine 6 (finished) created at:
main.main()
/home/erwo/test.go:25 +0x15f
==================
peach 2
grape 2
lemon 4
Found 2 data race(s)
exit status 66
答案 1 :(得分:5)
每个goroutine都会发生一些事情:
i
的值,因为它是。i
的值。 无法保证这两件事会以原子方式发生,或者以哪种顺序发生在哪些goroutines上。
为了获得您想要的结果,您可以:
i
的访问权限(但有时候会失去并列论点)i
作为参数传递给您的函数(go func(i int){}(i)
)。 (像Krom的回答)我建议2.但我也建议不要使用goroutine命令作为随机源。