2016-08-05 65 views
3

我一定錯過了一些東西,因爲我還沒有找到在線解答這個非常基本的問題。我正在使用能夠保存三個int值的緩衝通道。等待一個緩衝通道充滿

然後,我使用三個goroutines來填充它,並且我想在緩衝通道已滿時執行操作。

這裏是一個片段說明問題:

func main() { 
    // Initialization of the slice a and 0 < n < len(a) - 1. 
    difs := make(chan int, 3) 
    go routine(a[:n], difs) 
    go routine(a[n + 1:], difs) 
    go routine(a[n - 1:n + 1], difs) 

    fmt.Println(<-difs) // Display the first result returned by one of the routine. 
} 

func routine(a []int, out chan<- int) { 
    // Long computation. 
    out <- result 
} 

我想更新我的代碼,以便fmt.Println(<-difs)顯示器int數組當所有的值已經計算出來。我可以使用三次<-difs,但我想知道Go是否提供了更乾淨的方法。

+0

也許你應該使用[select](https://tour.golang.org/concurrency/5) –

+3

這聽起來就像[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) - 你通常不會等待頻道充滿,因爲你可以'然後同時從中消費價值。您希望等待goroutine完成,這是您使用sync.WaitGroup的原因。 – JimB

回答

4

等待使用信道本身,這樣工作的示例代碼:

package main 

import "fmt" 

func main() { 
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} // Initialization of the slice a and 0 < n < len(a) - 1. 
    difs := make(chan int, 3) 

    go routine(a[0:4], difs) 
    go routine(a[4:8], difs) 
    go routine(a[8:12], difs) 

    result := []int{<-difs, <-difs, <-difs} 

    fmt.Println(result) // Display the first result returned by one of the routine. 
} 

func routine(a []int, out chan<- int) { 
    result := 0 // Long computation. 
    for _, v := range a { 
     result += v 
    } 
    out <- result 
} 

輸出:

[10 42 26] 
+0

簡單而有效,謝謝!我贊成其他答案,因爲它使用'sync.WaitGroup',這個解決方案似乎是這類問題的標準解決方案。 –

+0

@ armand-grillet只需要3個頻道就不需要sync.WaitGroup,您可以使用頻道本身進行同步。 – 2016-08-05 16:33:01

+0

當您編寫可變數量的消息時,等待組是特別理想的,因爲可以在啓動新的goroutine時以及在完成時添加或刪除它們。 – Kaedys

4

函數len()支持通道,返回通道中未讀隊列元素的數量。但是,您必須運行一個循環來定期檢查它。

處理,這是使用一個sync.WaitGroup,像這樣的傳統方法:

func main() { 
    // Initialization of the slice a and 0 < n < len(a) - 1. 
    var wg sync.WaitGroup 
    wg.Add(3) 
    difs := make(chan int, 3) 
    go routine(a[:n], difs, &wg) 
    go routine(a[n + 1:], difs, &wg) 
    go routine(n - 1:n + 1], difs, &wg) 

    wg.Wait() // blocks until wg.Done() is called 3 times 
    fmt.Println(<-difs) // Display the first result returned by one of the routine. 
} 

// NOTE: This MUST accept a POINTER to the waitgroup. They are not copy-safe. 
func routine(a []int, out chan<- int, wg *sync.WaitGroup) { 
    defer wg.Done() 
    // Long computation. 
    out <- result 
}