【发布时间】:2021-02-04 16:03:35
【问题描述】:
我正在解决 A Tour of Go 中的练习,Equivalent Binary Tree。
这个练习需要实现一个Walk 函数,该函数应该遍历一棵树并将所有值从树中有序地发送到通道。
练习声明指出:
...我们将使用 Go 的并发和通道来编写一个简单的解决方案。
阅读该行,我认为以一种为每个左/右子树启动一个 goroutine 并使 Walk 比非并发运行更快(关于时间复杂度)的方式来实现 Walk 是具有挑战性的版本。让我用代码更详细地解释一下。
这是我早期的Walk代码:
func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
if t == nil { return }
lch, rch := make(chan int), make(chan int)
go Walk(t.Left, lch)
for v := range lch { ch <- v }
ch <- t.Value
go Walk(t.Right, rch)
for v := range rch { ch <- v }
return
}
它肯定使用 goroutines,但实际上与没有 goroutines 的遍历没有什么不同,因为 ealry for v := range lch { ... } 会延迟 go Walk(t.Right, rch) 直到它结束。
向上移动go Walk(t.Right, rch)没有任何区别:
func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
if t == nil { return }
lch, rch := make(chan int), make(chan int)
go Walk(t.Left, lch)
go Walk(t.Right, rch)
for v := range lch { ch <- v }
ch <- t.Value
for v := range rch { ch <- v }
}
go Walk(t.Left, lch) 遍历整个左子树(以蓝色为根),从lch 发送的值立即接收。
go Walk(t.Right, rch) 也尝试向前走,但 被阻塞,因为右子树最左侧节点(红色)上的 ch <- t.Value 这样做并传播阻塞。这种状态一直持续到达到for v := range rch { ch <- v }。
我的问题:
如何实现Walk,让goroutines(对应左或右)尽可能避免被ch <- t.Value阻塞?
【问题讨论】:
-
记住,
go Somefunc()正在一个新的 goroutine 中运行Somefunc。 -
一旦你的代码到达
range { }块,它就永远不会离开。range非常适合处理频道,但在您在频道上调用close之前,请将其视为无限循环。 -
@NateH06 它确实被关闭了,在第一行的
defer中。 -
这个问题是discussed on meta。如果任何亲密的选民愿意分享他们在问题中遗漏的内容或不清楚的地方,那将不胜感激。
标签: go concurrency