2016-08-08 5 views
0

並列のゴルーチンで複雑なプログラムを作成しようとしています。それはチャンネルを持つ私の最初のプログラムです;)各ゴルーチンは配列を返し、残念なことに、結果は "ランダム"です。もし私がプログラムを10回実行すると、私は10種類の結果が出ます:(配列チャンネルを共有するゴルーチン:データの競合を解決しようとしています

これは私のプログラムを単純化したものですが、結果は良いです(あまりに単純すぎるかもしれないが) 4つのデータレースがあります。

は私が近い()関数を持っていたことを試みたが、それは働いていませんでした。

は、あなたが間違いを見つけるために私を助けてもいいですか?事前にありがとうございました!

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

未定義の順序でチャンネルに10ものを入れるので、ここで何が起こると思いますか? – ams

答えて

7

このフィックスには2つの部分があります。ゴルーチン間でスライスを共有しないでください。 mainで同期してqueueを超えて範囲を指定します。

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) 
} 

xスライスをゴルーチン間で共有する理由はありません。各ゴルーチンに別のスライスが必要な場合は、それぞれに新しいスライスを定義します。 1つのスライスを共有すると、常に余分な同期が必要になります。

他のレースは、queueからsliceスライスに加えて、最後のfmt.Printlnの間にあります。すべての値が読み込まれるまで印刷したくないので、並行する必要はありません。そのため、最終値を印刷する前に範囲のループを完全に終了してください。

関連する問題