2017-10-06 105 views
-2

我需要並行運行多個函數。
如果函數返回true(在通道上發送true),那麼最終結果應該是true與golang中的通道卡住

如何使用goroutines和通道實現此目的?

// Some performance intensive function 
func foo(i int, c chan bool) { 
    // do some processing and return either true or false 
    c <- true // or false 
} 

func main() { 
    flg := false 
    ch := make(chan bool) 
    for i := 0; i < 10; i++ { 
     go foo(i, ch) 
    } 
    // If even once foo() returned true then val should be true 
    flg = flg || <-ch 
} 
+0

「我如何使用頻道實現此目標?」 ---你有什麼理由必須使用它的渠道? – zerkms

+1

請向我們展示您的嘗試。你的代碼根本不使用頻道。 – Flimzy

+0

(同樣,你最好使用'gofmt',因爲你的代碼不容易閱讀) – Flimzy

回答

0

你只能從通道接收一個值(這將是由foo()調用一個發送的值,不可預知其中許多) ,但你想收到所有。

所以使用for循環,它收到你送(送)儘可能多的價值:

for i := 0; i < 10; i++ { 
    flg = flg || <-ch 
} 

雖然在你的情況下,將接收到足夠的循環,直到一個true值,因爲這將確定flg的最終值,但仍建議接收所有其他值,其餘的goroutine將被阻止(因爲ch是無緩衝的通道)。在這個例子中它並不重要,但是在「真實生活」的應用程序中,它會導致goroutines永久停留(內存泄漏)。

如果你不想等待所有foo()調用來完成,(只要遇到一個true值)爲儘快恢復,一個選項是讓ch緩衝,因此所有夠程可以在發送值它沒有被阻擋。而你並不需要接受(因此等待)這種方式,所有的foo()調用來完成:

ch := make(chan bool, 10) 
for i := 0; i < 10; i++ { 
    go foo(i, ch) 
} 

flg := false 
for i := 0; i < 10; i++ { 
    if <-ch { 
     flg = true 
     break 
    } 
} 

選擇這種方法,你應該提供手段取消夠程,其工作不再需要以避免不必要的CPU (和內存)使用情況。 context.Context是這樣一個意思,在這裏閱讀更多關於它:Close multiple goroutine if an error occurs in one in go

1

您可能會開始從通道ch閱讀和設置flgtrue一旦你得到真正的結果。就像這樣:

//flg = flg || <- ch 
for res := range ch { 
    if res { 
     flg = true 
    } 
} 

這樣的工作,但有一個嚴重的缺點 - for環從通道將無限等待新值。停止循環的習慣方法是關閉頻道。你可以這樣做:運行一個獨立的goroutine,等待所有goroutines退出。 Go提供了一個非常方便的工具來做到這一點 - sync.WaitGroup

定義它在全球範圍內,從而每一個夠程可以訪問它:

var (
    wg sync.WaitGroup 
) 

然後在每次啓動時的goroutine你添加一個夠程等待組:

for i := 0; i < 10; i++ { 
    wg.Add(1) // here 
    go foo(i, ch) 
} 

當夠程結束它調用wg.Done方法來標記它。

func foo(i int, c chan bool) { 
    //do some processing and return either true or false 
    c <- true //or false 
    wg.Done() // here 
} 

然後sepatate goroutine等待,直到所有foo goroutines退出並關閉通道。 wg.Wait塊,直至全部完成:

go func() { 
    wg.Wait() 
    close(ch) 
}() 

一起:https://play.golang.org/p/8qiuA29-jv