如果我知道它们是有限的,我应该消耗所有golang频道的值吗?

时间:2014-12-28 05:39:36

标签: go goroutine

我正在研究Concurrency sectionA Tour of Go,我对使用有限通道的Go约定感到好奇。在本练习中,我需要从两个通道读取值,并确定值是否相同且顺序相同。如果没有,我可以立即从我的方法返回false。但是,如果我这样做,Go会自动为我清理我的频道,还是我的goroutines会永远悬空并消耗资源?

处理这个的最好方法是将一个取消通道传递给我的goroutines,但由于goroutines读取了有限数量的数据,所以只消耗所有数据似乎很好。在现实生活中处理这种情况的最佳方法是什么?

2 个答案:

答案 0 :(得分:3)

Andrew Gerrand's talk at Gopherconslide 37上涵盖了这个确切的问题。

  

创建一个退出频道并将其传递给每个助行器。通过关闭退出   当相同的退出时,任何正在运行的步行者都会被终止。

func Same(t1, t2 *tree.Tree) bool {
    quit := make(chan struct{})
    defer close(quit)
    w1, w2 := Walk(t1, quit), Walk(t2, quit)
    for {
        v1, ok1 := <-w1
        v2, ok2 := <-w2
        if v1 != v2 || ok1 != ok2 {
            return false
        }
        if !ok1 {
            return true
        }
    }
}

答案 1 :(得分:2)

使用戒烟渠道, 正如在中讨论的那样 Go Concurrency Patterns: Pipelines and cancellation 博客文章 和Heath Borders&#39; answer, 通常是一个好主意。

还有 golang.org/x/net/context package 在讨论中 Go Concurrency Patterns: Context 博客文章增加了超时,截止日期和其他功能。

然而,要直接解决:

  

将自动为我清理我的频道

这取决于通道缓冲以及通道的写入方式。

E.g。

func writeValues(n int, c chan int) {
    for i := 0; i < n; i++ {
        c <- i
    }
    log.Println("writeValues", n, "done")
}

func main() {
    ch1 := make(chan int, 12)
    ch2 := make(chan int, 6)
    ch3 := make(chan int)

    go writeValues(10, ch1)
    go writeValues(11, ch2)
    go writeValues(12, ch3)

    time.Sleep(time.Second) // XXX
}

Playground

这里第一个goroutine将完成,ch1(以及其中缓冲的任何内容)将被垃圾收集和清理。 然而,后来的两个goroutine将阻止等待,直到他们可以写出所有的值。垃圾收集器永远不会触及ch2ch3,因为阻塞的goroutine会保留对它们的引用。 注意,如果从频道中读取的项目少至五个,则ch2 清除。

通常,在执行以下操作时,您只能依赖于此:

    errc := make(chan error, 1)
    go func() { errc <- someErrorReturningFunc() }()

如果被调用的函数无法取消它,那么这是一个常见的习语。 您可以执行此操作并在不从errc读取的情况下提前中止/返回,并且知道在函数最终返回时将清除goroutine和通道。 errc频道的缓冲区大小非常重要。