当试图解决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?
}
答案 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
}