英文:
Processing arrays in Go parallel gives unexpected results
问题
我对于在Go语言中并行计算相关性很感兴趣。我遇到的主要问题是所有的Go进程似乎执行完全相同的计算。我在这里用一个非常简单的例子重现了这个问题。
我得到的结果是:
4 + 50 = 54
4 + 50 = 54
4 + 50 = 54
而不是:
1 + 20 = 21
2 + 30 = 32
3 + 40 = 43
如果我将"wg.Wait()"移到上面,我可以得到正确的结果,但没有并行性
谢谢您提前的评论!
package main
import (
"fmt"
"runtime"
"sync"
)
func process_array(x, y int) int {
r := x + y
return r
}
func main() {
a1 := []int{0, 1, 2, 3, 4}
a2 := []int{10, 20, 30, 40, 50}
runtime.GOMAXPROCS(8)
var wg sync.WaitGroup
for i := 1; i < 4 ; i++ {
wg.Add(1)
go func() {
defer wg.Done()
x :=process_array(a1[i],a2[i])
fmt.Println(a1[i], "+", a2[i], "=", x)
}()
//wg.Wait() give the good result
//but it is not parallel processing
// 1 + 20 = 21
// 2 + 30 = 32
// 3 + 40 = 43
}
wg.Wait() // give a repetition of the same result :
// 4 + 50 = 54
// 4 + 50 = 54
// 4 + 50 = 54
}
英文:
I am interested to calculate correlations in parallel in Go. The main problem I have is that all the Go processes seems to execute exactly the same calculation. I reproduced here the problem with a very simple example.
I obtain :
4 + 50 = 54
4 + 50 = 54
4 + 50 = 54
instead of :
1 + 20 = 21
2 + 30 = 32
3 + 40 = 43
If I move up "wg.Wait()" I obtain the good result but no parallelism
Thank's in advance for your comments !
package main
import (
"fmt"
"runtime"
"sync"
)
func process_array(x, y int) int {
r := x + y
return r
}
func main() {
a1 := []int{0, 1, 2, 3, 4}
a2 := []int{10, 20, 30, 40, 50}
runtime.GOMAXPROCS(8)
var wg sync.WaitGroup
for i := 1; i < 4 ; i++ {
wg.Add(1)
go func() {
defer wg.Done()
x :=process_array(a1[i],a2[i])
fmt.Println(a1[i],"+", a2[i],"=", x)
}()
//wg.Wait() give the good result
//but it is not parallel processing
// 1 + 20 = 21
// 2 + 30 = 32
// 3 + 40 = 43
}
wg.Wait() // give a repetition of the same result :
// 4 + 50 = 54
// 4 + 50 = 54
// 4 + 50 = 54
}
答案1
得分: 3
你在所有的goroutine中访问的是同一个i
的副本。你看到的输出是因为循环在任何goroutine开始执行之前恰好完成。
这意味着在所有的goroutine中,i
具有相同的值,即它在循环中的最后一个值。
通过将i
作为参数传递给每个goroutine,从而在每个goroutine中操作一个副本,可以解决这个问题。
当你在循环中添加wg.Wait()
时,你看到了你期望的结果,因为你引入了同步,等待goroutine完成后再启动下一个。这意味着执行实际上是串行的,而不是并行的。
下面是更新后的代码,它按你的期望工作:
package main
import (
"fmt"
"runtime"
"sync"
)
func process_array(x, y int) int {
r := x + y
return r
}
func main() {
a1 := []int{0, 1, 2, 3, 4}
a2 := []int{10, 20, 30, 40, 50}
runtime.GOMAXPROCS(8)
var wg sync.WaitGroup
for i := 1; i < 4; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
x := process_array(a1[i], a2[i])
fmt.Println(a1[i], "+", a2[i], "=", x)
}(i)
//wg.Wait() give the good result
//but it is not parallel processing
// 1 + 20 = 21
// 2 + 30 = 32
// 3 + 40 = 43
}
wg.Wait() // give a repetition of the same result :
// 4 + 50 = 54
// 4 + 50 = 54
// 4 + 50 = 54
}
英文:
You're accessing the same copy of i
in all goroutines. The output you see is because the loop happens to finish before any of the goroutines start executing.
This means that i
has the same value in all goroutines, i.e. the last value it had in the loop.
Passing i
as an argument to each of your goroutines, thereby operating on a copy per goroutine instead, solves this problem.
The reason you saw the result you expected when you added wg.Wait()
in the loop is because you then introduced synchronization, waiting for the goroutine to finish before starting the next one. That means the execution was in fact serial, not parallell.
Here's the updated code, which works as you'd expect:
package main
import (
"fmt"
"runtime"
"sync"
)
func process_array(x, y int) int {
r := x + y
return r
}
func main() {
a1 := []int{0, 1, 2, 3, 4}
a2 := []int{10, 20, 30, 40, 50}
runtime.GOMAXPROCS(8)
var wg sync.WaitGroup
for i := 1; i < 4; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
x := process_array(a1[i], a2[i])
fmt.Println(a1[i], "+", a2[i], "=", x)
}(i)
//wg.Wait() give the good result
//but it is not parallel processing
// 1 + 20 = 21
// 2 + 30 = 32
// 3 + 40 = 43
}
wg.Wait() // give a repetition of the same result :
// 4 + 50 = 54
// 4 + 50 = 54
// 4 + 50 = 54
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论