2016-08-19 86 views
2

我有以下代碼:推遲關閉多個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 
} 

這導致死鎖第18行:

for v := range stuff {...} 

問題(我認爲)是,我不是推遲對FANIN功能關閉返回一個只讀通道。我不知道何時推遲它,因爲它需要等待多個goroutine的結束才能完成。

什麼是解決這種僵局的慣用方法?這段代碼甚至是慣用的嗎?

謝謝!

GoPlay

回答

2

您將錯誤是原因正確未關閉fanIn的通道。您可以使用sync.WaitGroup來解決問題:

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

令人驚歎。我想我需要一個sync.WG,但我沒有想到在另一個goroutine中使用它。有時候很容易。謝謝! –

+0

只爲了claritiy的緣故:沒有辦法只使用chan原語?我們完全需要一個WaitGroup來關閉fanIn(或合併)func的out-chan? –

+0

如果您提前知道操作次數,例如,從固定數量的例程到達該通道的消息數量,則最好僅使用通道進行同步。敵人的例子,只是'for'循環(不是'範圍')通過信道一段時間。 – abhink