2016-08-08 59 views
0

Ich versuche, ein komplexes Programm mit parallelen Göroutinen zu schreiben. Es ist mein erstes Programm mit Kanälen;) Jede goroutine gibt ein Array zurück und leider ist das Ergebnis "zufällig". Wenn ich 10 Mal das Programm laufe, habe ich 10 verschiedene Ergebnisse :(Goroutines teilen einen Array-Kanal: Versuchen, Datenrennen zu lösen

Dies ist eine über Vereinfachung meines Programms, die Ergebnisse sind gut (vielleicht, weil es zu einfach ist), aber wenn ich es mit -Race Argument laufen, gibt es vier Daten Rennen.

ich versuchte, ein close() Funktion hatte, aber es hat funktioniert nicht.

Mögest du mir helfen, den Fehler zu finden? Vielen Dank im Voraus!

package main 

import "fmt" 
import "sync" 
import "strconv" 


func cat_strings(a int, b string) []string{ 
    var y []string 

    j := strconv.Itoa(a) 
    y = append(y, j) 
    y = append(y, b) 
    return y 
} 

func main() { 
    var slice []string 
    var wg sync.WaitGroup 
    var x []string 

    queue := make(chan []string, 10) 

    wg.Add(10) 
    for i := 0; i < 10; i++ { 
     go func(i int) { 
      defer wg.Done() 
      x = cat_strings(i, "var") 
      queue <- x 
     }(i) 

    } 
    //close(queue) 

    go func() { 
     defer wg.Done() 
     for t := range queue { 
      slice = append(slice, t...) 
     } 
    }() 

    wg.Wait() 
    fmt.Println(slice) 
} 
+0

Sie legen 10 Dinge in einer unbestimmten Reihenfolge in einen Kanal, so dass ich nicht sicher bin, was Sie hier erwartet haben? – ams

Antwort

7

Es gibt zwei Stücke zu diesem Fix, teilen Sie nicht die Scheiben zwischen goroutines, und dann über queue synchron in main.

import (
    "fmt" 
    "strconv" 
    "sync" 
) 

func cat_strings(a int, b string) []string { 
    var y []string 

    j := strconv.Itoa(a) 
    y = append(y, j) 
    y = append(y, b) 
    return y 
} 

func main() { 
    var slice []string 
    var wg sync.WaitGroup 

    queue := make(chan []string, 10) 

    wg.Add(10) 
    for i := 0; i < 10; i++ { 
     go func(i int) { 
      defer wg.Done() 
      queue <- cat_strings(i, "var") 
     }(i) 

    } 

    go func() { 
     wg.Wait() 
     close(queue) 
    }() 

    for t := range queue { 
     slice = append(slice, t...) 
    } 

    fmt.Println(slice) 
} 

Es gibt keinen Grund für die zusätzlichen x Slice zwischen goroutines teilst. Wenn jede Goroutine eine andere Schicht benötigt, definieren Sie jeweils eine neue. Das Teilen eines einzelnen Slice erfordert immer eine zusätzliche Synchronisation.

Das andere Rennen ist zwischen der goruoutine, die von queue an die slice Scheibe anfügt, und der abschließenden fmt.Println. Es gibt keinen Grund dafür, dass diese gleichzeitig auftreten, da Sie nicht drucken möchten, bis alle Werte gelesen wurden. Beenden Sie also die For-Range-Schleife vollständig, bevor Sie den endgültigen Wert drucken.