2016-03-18 5 views
2

Ich bin interessiert, Korrelationen parallel in Go zu berechnen. Das Hauptproblem, das ich habe, ist, dass alle Go-Prozesse genau dieselbe Berechnung ausführen. Ich habe hier das Problem mit einem sehr einfachen Beispiel reproduziert. I erhalten:Die Verarbeitung von Arrays in Go parallel gibt unerwartete Ergebnisse

4 + 50 = 54 
4 + 50 = 54 
4 + 50 = 54 

statt:

1 + 20 = 21 
2 + 30 = 32 
3 + 40 = 43 

Wenn ich nach oben "wg.Wait()" Ich habe das gute Ergebnis zu erhalten, aber keine Parallelität :( den Dank im Voraus für Ihre Kommentare!

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 

    } 
+3

FAQ: https://golang.org/doc/faq#closures_and_goroutines – JimB

+0

Beachten Sie, dass praktisch, Sie möchten Ihre goroutines geben größere Aufgaben (zB, wenn Sie N cpus haben, geben Sie jede 1/n zu tun). Eine Ergänzung ist sehr schnell, und die Koordination zum Starten eines Threads und so weiter dauert logner. – twotwotwo

Antwort

3

Sie die gleiche Kopie von i in allen goroutines erreichbar. die Ausgabe, die Sie sehen, ist, weil die Schleife, bevor irgendwelche unterwegs zu beenden geschieht Routinen starten die Ausführung.

Das bedeutet, dass i den gleichen Wert in allen goroutines hat, d. H. Den letzten Wert, den es in der Schleife hatte.

i als ein Argument zu jedem Ihrer goroutines zu übergeben und dabei auf einer Kopie pro goroutine statt, löst dieses Problem.

Der Grund, warum Sie das Ergebnis erwartet haben, als Sie wg.Wait() in die Schleife eingefügt haben, ist, weil Sie dann die Synchronisation eingeführt haben und darauf warten, dass die Goroutine beendet wird, bevor die nächste gestartet wird. Das bedeutet, dass die Ausführung tatsächlich seriell und nicht parallel war.

Hier ist der aktualisierte Code, die, wie Sie arbeitet erwarten:

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 

} 
+0

oder das gemeinsame "i: = i" idom: http://play.golang.org/p/Zcof5HLrQr – JimB

+0

Ja, das funktioniert auch. Ich finde diesen Weg klarer. –

+0

wow! beeindruckende Lösung, einfach aber schwer zu finden! Vielen Dank ! – Fred

Verwandte Themen