【问题标题】:How to loop on a buffered channel without deadlocking?如何在缓冲通道上循环而不死锁?
【发布时间】:2014-05-26 04:13:48
【问题描述】:

我想知道如何排空/关闭缓冲通道,以免陷入僵局?我正在使用 range 来循环通道,但似乎虽然它们是“读取”的,但它们并没有像非缓冲通道那样被关闭。

package main

func main() {

    cp := 2
    ch := make(chan string, cp)

    for i := 0; i < cp; i++ {
        go send(ch)
    }
    go send(ch)

    for lc := range ch {
        print(lc)

    }

}

func send(ch chan string) {

    ch <- "hello\n"

}

Play

【问题讨论】:

    标签: concurrency go channel


    【解决方案1】:

    您可以使用close() builtin 关闭频道。这必须在所有并发处理完成后调用。你如何做到这一点取决于你想做什么。

    在您当前的架构中,您似乎必须建立一个全局状态,该状态会跟踪您的所有进程并确定最后一个进程是否完成。例如,可以通过使用sync.WaitGroup 来实现这种状态。

    func send(c chan string, wg *sync.WaitGroup) {
        defer wg.Done()
        // ...
    }
    
    wg := &sync.WaitGroup{}
    
    for i := 0; i < cp; i++ {
        wg.Add(1)
        go send(ch, wg)
    }
    wg.Add(1)
    go send(ch, wg)
    
    wg.Wait()
    close(ch)
    
    for e := range(ch) {
        // ...
    }
    

    请注意,关闭通道然后对其进行迭代只会给您在通道中排队的元素。这意味着任何想要在通道中放入值的 goroutine 在通道关闭时都不能再这样做了。

    【讨论】:

    • 为什么wg.Add(1)上面有go send(ch, wg)(在for循环之后)?我认为这是一个错字,对吧?
    • 没有错字。对于每个修改通道的 goroutine,您将一个数字添加到等待组。考虑阅读文档中的示例。
    • 对...我没有看到 for 循环之外的 goroutine。
    猜你喜欢
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 2017-09-06
    • 2021-12-25
    • 1970-01-01
    • 2018-06-24
    • 2019-09-15
    • 2011-10-09
    相关资源
    最近更新 更多