在Go语言中并行处理数组会产生意外的结果

huangapple go评论73阅读模式
英文:

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()"移到上面,我可以得到正确的结果,但没有并行性 在Go语言中并行处理数组会产生意外的结果

谢谢您提前的评论!

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 在Go语言中并行处理数组会产生意外的结果
Thank's in advance for your comments !

   package main
    
    import (
        &quot;fmt&quot;
        &quot;runtime&quot;
        &quot;sync&quot;
    )
    
    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 &lt; 4 ; i++ {
            wg.Add(1)
            go func() {
                defer wg.Done()
                x :=process_array(a1[i],a2[i])
                fmt.Println(a1[i],&quot;+&quot;, a2[i],&quot;=&quot;, 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 (
	&quot;fmt&quot;
	&quot;runtime&quot;
	&quot;sync&quot;
)

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 &lt; 4; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			x := process_array(a1[i], a2[i])
			fmt.Println(a1[i], &quot;+&quot;, a2[i], &quot;=&quot;, 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

}

huangapple
  • 本文由 发表于 2016年3月19日 03:20:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/36092665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定