2016-08-05 62 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 
}