Go 读取永久循环中两个通道的输出
我正在做树的练习。我已尝试实现与下面所述相同的功能Go 读取永久循环中两个通道的输出,go,Go,我正在做树的练习。我已尝试实现与下面所述相同的功能 func Same(t1, t2 *tree.Tree) bool { ch1 := make(chan int) ch2 := make(chan int) go Walk(t1, ch1); go Walk(t2, ch2); for c := range ch1 { d := <- ch2 if c-d !=0 { return fal
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1);
go Walk(t2, ch2);
for c := range ch1 {
d := <- ch2
if c-d !=0 {
return false
}
}
return true
}
func-Same(t1,t2*tree.tree)bool{
ch1:=制造(成交量)
ch2:=制造(成交量)
步行(t1,ch1);
步行(t2,ch2);
对于c:=范围ch1{
d:=这里有一个问题,您没有为walk函数中的右子树向通道发送值。但在另一侧接收它,这就是死锁错误的原因。因为您从通道接收到的右子树值从未发送过。这里有一个问题,您没有为右子树向通道发送值在walk函数中。但在另一端接收它,这就是死锁错误的原因。因为如果右子树从未发送,您将从通道接收一个值。在遍历树后应关闭通道,以在树相等的情况下终止范围循环(请注意:Same
在中缀遍历树相等时返回true,不要求它们的结构相等)
注意:如果树的项目数不同,并且没有发现差异,则应检查第二个通道是否已关闭(“线程饥饿”在这里比“死锁”更合适)。如果树相等,则应在遍历树后关闭通道以终止范围循环(请注意:Same
在中缀遍历树相等时返回true,不要求它们的结构相等)
注意:您应该检查第二个通道是否已关闭,以防树具有不同数量的项,并且没有发现差异(“线程饥饿”在这里比“死锁”更合适).您看到死锁的原因很简单:您在ch1
上运行,但从未关闭它,因此for循环从未终止
您可以通过手动在每个树上迭代一定次数来修复此问题,就像main()
中的0..10循环一样:
//这一点决定了树
//t1和t2包含相同的值。
func-Same(t1,t2*tree.tree)bool{
ch1:=制造(成交量)
ch2:=制造(成交量)
步行(t1,ch1)
步行(t2,ch2)
对于i:=0;i<10;i++{
c:=您看到死锁的原因很简单:您在ch1
上运行,但从未关闭它,因此for循环从未终止
您可以通过手动在每个树上迭代一定次数来修复此问题,就像main()
中的0..10循环一样:
//这一点决定了树
//t1和t2包含相同的值。
func-Same(t1,t2*tree.tree)bool{
ch1:=制造(成交量)
ch2:=制造(成交量)
步行(t1,ch1)
步行(t2,ch2)
对于i:=0;i<10;i++{
c:=小心,结果可能会因树结构的不同而不同!原始代码检查树的中缀遍历是否相同,而此代码检查后缀遍历。两者的限制性都比检查树是否实际相同要小。错误原因是没有将值发送到在另一端接收。如果条件应该满足,那么我们还必须向通道发送一个值。在右节点漫游后发送当前节点的值违反了二叉树的有序语义。并且他的原始代码肯定是在右节点上调用walk。a)功能不应更改B)避免死锁的唯一原因是后缀遍历不同,而中缀相同。调用相同的(x,x)仍然会导致死锁,当通道耗尽时,仍然会发生同样的情况,返回true。是的,我会仔细研究,结果可能会因树结构而异!原始代码检查树的中缀遍历是否相同,而此代码检查后缀遍历。这两个与检查树是否实际相同相比,它们的限制性更小。错误的原因是没有向另一端接收的通道发送值。如果满足条件,则我们还必须向通道发送值。在正确的节点行走后发送当前节点的值违反了二叉树的有序语义。他的原始代码肯定是在右边的节点上调用Walk。A)功能不应该更改B)死锁是因为后缀遍历不同而避免的,而中缀是相同的。调用相同的(x,x)仍然会导致死锁,当通道耗尽时,仍然会发生在打算返回true时。是的,我会研究它
func WalkTreeAndThenCloseChannel(t *tree.Tree, ch chan int) {
Walk(t, ch)
close(ch)
}
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go WalkTreeAndThenCloseChannel(t1, ch1);
go WalkTreeAndThenCloseChannel(t2, ch2);
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i := 0; i < 10; i++ {
c := <-ch1
d := <-ch2
if c-d != 0 {
return false
}
}
return true
}
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
if t.Left != nil {
wg.Add(1)
Walk(t.Left, ch, wg)
}
ch <- t.Value
if t.Right != nil {
wg.Add(1)
Walk(t.Right, ch, wg)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
var wg1 sync.WaitGroup
wg1.Add(1)
go Walk(t1, ch1, &wg1)
go func() {
wg1.Wait()
close(ch1)
}()
var wg2 sync.WaitGroup
wg2.Add(1)
go Walk(t2, ch2, &wg2)
go func() {
// not strictly necessary, since we're not ranging over ch2, but here for completeness
wg2.Wait()
close(ch2)
}()
for c := range ch1 {
d := <-ch2
if c-d != 0 {
return false
}
}
return true
}