2017-10-10 9 views
2

私は1つのgo-routineをチャネルにオブジェクトを追加するために持っていますし、チャネルのオブジェクトを処理するために4 go-routinesがあります。処理は、配列にオブジェクトを追加するだけです。しかし、数回では、オブジェクトは最終的な配列から欠落しています。だから私は、ある時点でオブジェクトを収集するためにチャネルが停止していると仮定しています。私は次のコードを持っています:チャンネルからすべてのオブジェクトを収集していないルーチンを返します

package main 

import (
    "log" 
    "sync" 
) 

func main() { 
    j := 0 
    for { 
     if j == 10 { 
      break 
     } 
     wg := sync.WaitGroup{} 
     months := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"} 
     hits := make(chan string) 
     i := 0 
     wg.Add(1) 
     go func() { 
      defer close(hits) 
      for { 
       if i == 25 { 
        wg.Done() 
        return 
       } 
       for _, month := range months { 
        hits <- month 
       } 
       i++ 
      } 
     }() 

     temp := []string{} 
     for updateWorker := 1; updateWorker <= 4; updateWorker++ { 
      wg.Add(1) 
      go func() { 
       for hit := range hits { 
        temp = append(temp, hit) 
       } 
       wg.Done() 
       return 
      }() 
     } 

     wg.Wait() 

     log.Printf("length of temp %+v\n", len(temp)) 
     j++ 
    } 
} 

私はsyncライブラリを使ってルーチンを同期させています。出力が一貫しているかどうかをテストするために同じプロセスを10回繰り返します。

length of temp 175 

私は7桁の文字列を25回送信しているため、175です。 しかし、出力が175未満の場合は、理由がわかりません。私はルーチンに行くのは初心者です。だから誰でも私に理由を見つけるのを助けてくれますか?ありがとう。

答えて

4

問題がupdateWorkerゴルーチンすべてが(これまでのところは良い)hitsチャネルからの結果を収集することで、それらはすべてtempローカル変数非同期のに結果を格納します。これは問題ではありません。

複数のゴルーチンからのすべての変数へのアクセス(少なくとも1つは書き込み)は、同期する必要があります。

レースディテクタを有効にして実行すると、データレース(go run -race app.go)について悲鳴を上げる。

あなたは1にupdateWorkerゴルーチンの数を減らすならば、私たちはあなたのアプリケーションの単一のデータレース源を排除するので、それはすぐに、有効な結果が得られます。

for updateWorker := 1; updateWorker <= 1; updateWorker++ { 
    // ... 
} 

複数updateWorkerゴルーチンを維持したい場合は、その共有されるtemp変数へのアクセスを同期させる必要があります。 sync.Mutex

temp := []string{} 
mux := sync.Mutex{} 
for updateWorker := 1; updateWorker <= 4; updateWorker++ { 
    wg.Add(1) 
    go func() { 
     for hit := range hits { 
      mux.Lock() 
      temp = append(temp, hit) 
      mux.Unlock() 
     } 
     wg.Done() 
     return 
    }() 
} 

はまた、この単純な例では、あなたが(ロック)上記の同期も、それらの一つだけ持つと比べて、それはあまりパフォーマンス作るの追加、複数のupdateWorkerゴルーチンを使用して、何も得ていないことに注意してください。

正常に作業を配布し結果を収集するには、Is this an idiomatic worker thread pool in Go?