【问题标题】:Wait for a buffered channel to be full等待缓冲通道满
【发布时间】:2016-12-12 03:00:30
【问题描述】:

我一定错过了什么,因为我还没有在网上找到这个非常基本的问题的答案。我正在使用能够保存三个int 值的缓冲通道。

然后我使用三个 goroutine 来填充它,并且我想在缓冲通道满后执行操作。

这是一个解释问题的sn-p:

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(&lt;-difs) 在计算完所有值后显示int 的数组。我可以使用 3 次 &lt;-difs 但我想知道 Go 是否提供了更清洁的东西来做到这一点。

【问题讨论】:

  • 也许你应该使用select
  • 这听起来像XY Problem——你通常不会等待一个通道被填满,因为你不能同时使用它的值。你想等待 goroutines 完成,这就是你使用 sync.WaitGroup 的目的。

标签: go


【解决方案1】:

函数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
}

【讨论】:

    【解决方案2】:

    使用通道本身等待,就像这个工作示例代码:

    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]
    

    【讨论】:

    • 简单而有效,谢谢!我赞成另一个答案,因为它使用了sync.WaitGroup,这种解决方案似乎是此类问题的标准解决方案。
    • @armand-grillet 不需要同步。WaitGroup 这里只有 3 个频道,您可以使用频道本身进行同步。
    • Waitgroups 尤其适用于您要写入的消息数量不定的情况,因为它们可以在您启动新的 goroutine 以及它们完成时添加和减去。
    • 您也可以使用:result := make([]int, 3) for i := 0; i &lt; 3; i++ { result[i] = &lt;-difs } 获取更多频道。
    • 缺点是如果发送者例程之一在发送之前返回,接收例程将无限期阻塞。对于使用延迟 wg.Done() 的等待组版本,这不会发生。
    猜你喜欢
    • 2023-02-11
    • 2020-04-09
    • 2014-10-28
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多