2017-08-15 4 views
1

私は新しいです。私は同時性パターンについて学びたいと思っています。次のコードを実行すると、時には期待される結果(0〜9999の数字の完全な配列)が得られることがあります。他の時間私はちょうど表示された時間と "それはそれ"のメッセージを取得します。そして、時には私はちょうど "閉じたチャネル上の送信"エラーを取得します。ここで何がうまくいかないのでしょうか?Goルーチンが動作することがあります。時にはclose channelエラーが発生します。

package main 

import (
    "fmt" 
    "time" 
    "sync" 
) 

func JobsDispatcher(in chan int, data []int){ 
    for _, value := range data{ 
     in<-value 
    } 
    close(in) 
} 

func Worker(in chan int, out chan int, wg *sync.WaitGroup){ 
    wg.Add(1) 
    for{ 
     inMsg, ok := <-in 
     if !ok{ 
      wg.Done() 
      return 
     } 
     out <- inMsg 
    } 

} 

func PrintInt(out chan int){ 
    for { 
     outMsg, ok := <-out 
     if !ok{ 
      fmt.Println("") 
      fmt.Println("That's it") 
      return 
     } 
     fmt.Println(outMsg) 
    } 
} 

func ParallelPrint(data []int){ 
    var wg sync.WaitGroup 

    in := make(chan int) 
    out := make(chan int) 

    parallelStartTime := time.Now() 

    go JobsDispatcher(in, data) 

    for i:=0;i<5;i++{ 
     go Worker(in,out,&wg) 
    } 


    go func(){ 
     wg.Wait() 
     close(out) 
    }() 
    PrintInt(out) 

    fmt.Println(time.Since(parallelStartTime)) 

} 

func main(){ 
    data := make([]int,0) 
    for i:=0;i<10000;i++{ 
     data = append(data, i) 
    } 

    ParallelPrint(data) 
} 

答えて

5

これは簡単です。このため、WaitGroupのAddをgoroutineで使用することはありません。ゴルーチンを開始する前に、必ずそれを呼び出してください。

問題は、ゴルーチンの束を積み重ねてすぐにWaitを呼び出すことです。 Goは、POSIXやWindowsスレッドが保証されていないのと同じように、いつでもあなたのゴルーチンを実行すると約束していません。

この場合、スケジューラには今後実行するゴルーチンの束が与えられましたが、コードを最初に終了することに決めました。だからwg.Add()を実行する前にwg.Wait()close(out)を実行しました。すぐに戻りますそうでなければ、それはすべての労働者を追加することができます

for i:=0;i<5;i++{ 
    wg.Add(1) // Here, not inside Worker() 
    go Worker(in,out,&wg) 
} 

、あらゆる労働者はwg.Addと呼ばれている前wg.Waitを打つ、、:すなわち - あなたはそれがのためだゴルーチン外wg.Addを呼び出したい

3

チャネルを閉じます。

関連する問題