如何在没有死锁的情况下在缓冲通道上循环?

时间:2014-04-11 20:42:03

标签: concurrency go channel

我想知道如何排出/关闭缓冲的通道以便我不会陷入死锁?我正在使用范围循环通道,但似乎虽然它们是“读取”但它们并没有像非缓冲通道那样关闭。

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

1 个答案:

答案 0 :(得分: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都不能在频道关闭时执行此操作。