2016-08-19 7 views
2

私は次のコードを持っている:それはライン18上のデッドロックになり複数のGoroutinesを閉じることができますか?

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    t := time.Now() 
    stuff := fanIn(
     generator(4, 5, 6, 7), 
     generator(1, 2, 6, 3, 7), 
     generator(12, 15, 33, 40, 10), 
     generator(18, 13, 20, 40, 15), 
     generator(100, 200, 64000, 3121, 1237), 
    ) 

    for v := range stuff { 
     fmt.Println(v) 
    } 

    fmt.Println(t.Sub(time.Now())) 
} 

func generator(nums ...int) <-chan int { 
    out := make(chan int, 10) 
    go func() { 
     defer close(out) 
     for _, v := range nums { 
      out <- v 
     } 
    }() 
    return out 
} 

func fanIn(in ...<-chan int) <-chan int { 
    out := make(chan int, 10) 

    for _, v := range in { 
     go func(ch <-chan int) { 
      for val := range ch { 
       go func(c int) { out <- c }(val) 
      } 
     }(v) 
    } 

    return out 
} 

を:(と思う)

for v := range stuff {...} 

問題は、私はファンイン機能に密接に延期ていないよということです読み取り専用チャンネルを返します。複数のゴルーチンの終了を待つ必要があるので、いつ延期するのか分かりません。

このデッドロックを解決するための慣習的な方法は何ですか?このコードは慣用句ですか?

ありがとうございます!

GoPlay

答えて

2

あなたは、エラーの原因がfanInのチャネル非閉じたことについて正しいです。

func fanIn(in ...<-chan int) <-chan int { 
    // use a WaitGroup here 
    var wg sync.WaitGroup 
    out := make(chan int, 10) 

    for _, v := range in { 
     wg.Add(1) 
     go func(ch <-chan int) { 
      defer wg.Done() 
      for val := range ch { 
       out <- val 
      } 
     }(v) 
    } 

    // wait for wait groups to finish in another goroutine 
    go func() { 
     wg.Wait() 
     close(out) 
    }() 
    return out 
} 

Working code:あなたはこの問題を解決するためにsync.WaitGroupを使用することができます。

+0

素晴らしい。私はsync.WGが必要だと思ったが、別のゴルーチンでそれを使うとは思わなかった。とても簡単です。ありがとう! –

+0

ちょっと分かりました。ちょっとだけプリミティブを使う方法はありませんか? fanIn(またはmerge)funcのout-chanを閉じるにはWaitGroupが必要ですか? –

+0

事前に操作の数、たとえば一定数のゴルーチンからチャンネルに到着したメッセージの数などが分かっている場合は、チャンネルのみを使用して同期する方がよい場合があります。例のために、設定された回数だけチャネル上の 'for'ループ(' range'ではなく)です。 – abhink

関連する問題