2017-01-21 1 views
0

Ich bin relativ neu in der Go-Sprache. Obwohl ich es nicht hoffe, störe ich Sie vielleicht mit einer dummen Frage. Meine Entschuldigung im Voraus, nur für den Fall ...Gehen konkurrierende Worker-Routinen mit Slice-Typ Eingabe- und Ausgabekanäle

Hier ist mein Beispiel: Ich habe eine worker() -Funktion definiert, die von main() als eine Reihe von gleichzeitigen Go-Routinen aufgerufen wird. Eingangs- und Ausgangsdaten werden über einen Eingangs- und einen Ausgangskanal des Slice-Typs [] int bereitgestellt. In einem Fall funktioniert alles wie erwartet, im anderen Fall ist das Ergebnis fehlerhaft. Siehe die Kommentare im Code und die Programmausgabe unter dem Code.

Ehrlich gesagt, sehe ich nicht den tatsächlichen Unterschied zwischen beiden Code-Varianten. Was habe ich hier vermisst? Danke für irgendeinen Rat!

package main 

import "fmt" 
import "runtime" 

func worker(x_ch <-chan []int, y_ch chan<- []int, wid int) { 

    for x := range x_ch { 
     y := x 
     fmt.Println(" worker", wid, "x:", x) 
     fmt.Println(" worker", wid, "y:", y) 
     y_ch <- y 
    } 
} 

func main() { 

    n_workers := runtime.NumCPU() 
    n_len := 4 
    n_jobs := 4 
    x := make([]int, n_len) 
    x_ch := make(chan []int, 10) 
    y_ch := make(chan []int, 10) 

    for j := 0; j < n_workers; j++ { go worker(x_ch, y_ch, j) } 

    for k := 0; k < n_jobs; k++ { 

//  variant 1: works! 
     x = []int{k, k, k, k} 

//  variant 2: doesn't work! 
//  for i := range x { x[i] = k } 

     fmt.Println("main x:", k, x) 
     x_ch <- x 
    } 

    close(x_ch) 

    for i := 0; i < n_jobs; i++ { 
     z := <- y_ch 
     fmt.Println("  main y:", i, z) 
    } 
} 

richtige Ausgabe (Variante 1):

main x: 0 [0 0 0 0] 
main x: 1 [1 1 1 1] 
main x: 2 [2 2 2 2] 
main x: 3 [3 3 3 3] 
    worker 3 x: [3 3 3 3] 
    worker 3 y: [3 3 3 3] 
    worker 2 x: [2 2 2 2] 
    worker 2 y: [2 2 2 2] 
    worker 1 x: [0 0 0 0] 
    worker 1 y: [0 0 0 0] 
    worker 0 x: [1 1 1 1] 
    worker 0 y: [1 1 1 1] 
     main y: 0 [3 3 3 3] 
     main y: 1 [2 2 2 2] 
     main y: 2 [0 0 0 0] 
     main y: 3 [1 1 1 1] 

Wrong Ausgang (Variante 2):

main x: 0 [0 0 0 0] 
main x: 1 [1 1 1 1] 
main x: 2 [2 2 2 2] 
main x: 3 [3 3 3 3] 
    worker 3 x: [3 3 3 3] 
    worker 3 y: [3 3 3 3] 
     main y: 0 [3 3 3 3] 
    worker 0 x: [2 2 2 2] 
    worker 0 y: [3 3 3 3] 
     main y: 1 [3 3 3 3] 
    worker 1 x: [1 1 1 1] 
    worker 1 y: [3 3 3 3] 
     main y: 2 [3 3 3 3] 
    worker 2 x: [3 3 3 3] 
    worker 2 y: [3 3 3 3] 
     main y: 3 [3 3 3 3] 

Antwort

1

Der Unterschied ist, dass in der Variante 1, Sie sind ein anderes Segment zu senden jedes Mal, während in Variante 2, Sie die gleiche Scheibe jedes Mal senden (die eine über den for Schleifen erstellt). Ohne ein neues Segment zu erstellen, setzen Sie nur die Elemente des gleichen Segments auf unterschiedliche Werte, sodass die Goroutines sehen, welche Werte sich gerade im Segment befinden, wenn sie es betrachten. In Variante 2 wird main immer [3 3 3 3] angezeigt, da dies der Endwert ist, nachdem Sie die Schleife viermal durchlaufen haben. Der Wert eines Slice-Objekts enthält einen Verweis auf die zugrunde liegenden Elemente, nicht die Elemente selbst. Es gibt eine gute Erklärung der Scheiben here.

0

Vielen Dank für Ihre Erklärung, jetzt sehe ich, wo das Problem liegt. I hinzugefügt, um die Pointer-Adressen einen Debug-Code auszugeben, und das Ergebnis ist (mit slighty umformatiert Ausgang):

Variante 1:

main 0 x=[0 0 0 0] &x=0x1830e180 &x[0]=0x1830e1e0 
main 1 x=[1 1 1 1] &x=0x1830e180 &x[0]=0x1830e230 
main 2 x=[2 2 2 2] &x=0x1830e180 &x[0]=0x1830e270 
main 3 x=[3 3 3 3] &x=0x1830e180 &x[0]=0x1830e2a0 
    worker 3 x=[3 3 3 3] &x=0x1830e1d0 &x[0]=0x1830e2a0 
    worker 3 y=[3 3 3 3] &y=0x1830e2e0 &y[0]=0x1830e2a0 
     main 0 y=[3 3 3 3] &y=0x1830e2d0 &y[0]=0x1830e2a0 
    worker 0 x=[0 0 0 0] &x=0x1830e1a0 &x[0]=0x1830e1e0 
    worker 0 y=[0 0 0 0] &y=0x1830e370 &y[0]=0x1830e1e0 
     main 1 y=[0 0 0 0] &y=0x1830e360 &y[0]=0x1830e1e0 
    worker 1 x=[1 1 1 1] &x=0x1830e1b0 &x[0]=0x1830e230 
    worker 1 y=[1 1 1 1] &y=0x1830e400 &y[0]=0x1830e230 
     main 2 y=[1 1 1 1] &y=0x1830e3f0 &y[0]=0x1830e230 
    worker 2 x=[2 2 2 2] &x=0x1830e1c0 &x[0]=0x1830e270 
    worker 2 y=[2 2 2 2] &y=0x1830e480 &y[0]=0x1830e270 
     main 3 y=[2 2 2 2] &y=0x1830e470 &y[0]=0x1830e270 

Variante 2:

main 0 x=[0 0 0 0] &x=0x1830e180 &x[0]=0x1830e190 
main 1 x=[1 1 1 1] &x=0x1830e180 &x[0]=0x1830e190 
main 2 x=[2 2 2 2] &x=0x1830e180 &x[0]=0x1830e190 
main 3 x=[3 3 3 3] &x=0x1830e180 &x[0]=0x1830e190 
    worker 3 x=[3 3 3 3] &x=0x1830e1d0 &x[0]=0x1830e190 
    worker 3 y=[3 3 3 3] &y=0x1830e2a0 &y[0]=0x1830e190 
     main 0 y=[3 3 3 3] &y=0x1830e290 &y[0]=0x1830e190 
    worker 0 x=[3 3 3 3] &x=0x1830e1a0 &x[0]=0x1830e190 
    worker 0 y=[3 3 3 3] &y=0x1830e330 &y[0]=0x1830e190 
     main 1 y=[3 3 3 3] &y=0x1830e320 &y[0]=0x1830e190 
    worker 1 x=[3 3 3 3] &x=0x1830e1b0 &x[0]=0x1830e190 
    worker 1 y=[3 3 3 3] &y=0x1830e3c0 &y[0]=0x1830e190 
     main 2 y=[3 3 3 3] &y=0x1830e3b0 &y[0]=0x1830e190 
    worker 2 x=[3 3 3 3] &x=0x1830e1c0 &x[0]=0x1830e190 
    worker 2 y=[3 3 3 3] &y=0x1830e440 &y[0]=0x1830e190 
     main 3 y=[3 3 3 3] &y=0x1830e430 &y[0]=0x1830e190 
Verwandte Themen