2016-08-19 2 views
2

Ich habe den folgenden Code:Auf mehreren Gorroutinen aussetzen?

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 
} 

Es führt in eine Sackgasse auf der Linie 18:

for v := range stuff {...} 

Die Frage (glaube ich), ist, dass ich nicht die Nähe auf der Fanin Funktion aufzuschieben bin Das gibt einen schreibgeschützten Kanal zurück. Ich weiß nicht, wann ich es verschieben sollte, da es warten muss, bis das Ende von mehreren Goroutinen abgeschlossen ist.

Was ist der idiomatische Weg, diesen Deadlock zu lösen? Ist dieser Code sogar idiomatisch?

Danke!

GoPlay

Antwort

2

Sie sind richtig über die Ursache des Fehlers ist un-geschlossen fanIn ‚s-Kanal. Sie können eine sync.WaitGroup verwenden um das Problem zu beheben:

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.

+0

Erstaunlich. Ich dachte, ich würde eine sync.WG brauchen, aber ich dachte nicht daran, sie in einer anderen Goroutine zu benutzen. So einfach mal. Vielen Dank! –

+0

Nur um der Klarheit willen: Es gibt keine Möglichkeit, nur die chan-Primitive zu benutzen? Wir brauchen unbedingt eine WaitGroup, um den fanIn (oder merge) func out-chan zu schließen. –

+0

Wenn Ihnen die Anzahl der Vorgänge im Voraus bekannt ist, z. B. die Anzahl der Nachrichten, die aus einer festgelegten Anzahl von Gornoutinen auf dem Kanal ankommen, ist es möglicherweise besser, nur Kanäle zu synchronisieren. Foe Beispiel, nur 'for' Schleife (nicht' Bereich') über den Kanal für eine bestimmte Anzahl von Zeiten. – abhink

Verwandte Themen