在Go Tour等效二叉树上使用多个Goroutines

时间:2014-04-28 16:27:05

标签: go goroutine

当试图解决Go Tour中Equivalent Binary Trees问题的树步行部分时,显而易见的解决方案是使用recursion。其他解决方案,如闭包,在general question的答案中提供了如何解决问题。

我最初的想法是在步行的每一步都使用Goroutine。这不是一个更好的,更多的Go-onic(什么是Go等效的Pythonic?)解决方案?问题是我无法弄清楚如何A)在树走完后关闭通道,或者B)以树的步行完成的其他方式发出信号。较早的example使用2个通道,一个用于数据,一个用于退出信号。传递第二个通道不符合问题定义,并且仍然存在步行结束时的根问题。对于每个步行步骤,是否有一个优雅的解决方案与Goroutine,或递归是最好的解决方案?

func Walk(t *tree.Tree, ch chan int) {
    if t != nil {
        go Walk(t.Left, ch)
        ch <- t.Value
        go Walk(t.Right, ch)
    }
    //Done with this node, how do I know when all are done?
}

2 个答案:

答案 0 :(得分:1)

在步行的每个步骤中使用goroutine将无法正常工作。除了不知道何时可以关闭频道(我不知道一个好的解决方法)之外,您无法保证获得您想要的订购。例如,以下代码:

go fmt.Println(1)
go fmt.Println(2)
go fmt.Println(3)

可以打印123,132,213,231,312或321中的任何一个,具体取决于调度程序选择如何运行这些goroutine。这意味着您的Walk实施不再以正确的顺序为您提供值。

当你想要同时做某件事时,Goroutines才是正确的答案;鉴于必须严格排序到通道的输出,在这个问题上没有可用的并发性。

答案 1 :(得分:0)

您可以使用sync.WaitGroup

func internalWalk(t *tree.Tree, wg *sync.WaitGroup, ch chan int) {
    wg.Add(1)
    if t != nil {
        go Walk(t.Left, ch)
        ch <- t.Value
        go Walk(t.Right, ch)
    }
    wg.Done()
}
func Walk(t *tree.Tree, ch chan int) {
    var wg sync.WaitGroup
    internalWalk(t, &wg, ch)
    wg.Wait()
    //they are all done now, do something here
}