Concurrency GoLang教程中的死锁错误

Concurrency GoLang教程中的死锁错误,concurrency,go,Concurrency,Go,我正在尝试做这个教程- 这是我的密码 // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int) { if t != nil { Walk(t.Left, ch) ch <- t.Value Walk(t.Right,ch) } } // Same d

我正在尝试做这个教程-

这是我的密码

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
    if t != nil {
        Walk(t.Left, ch)
        ch <- t.Value
        Walk(t.Right,ch)
    }
}

// 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:= range ch1 {
        if i != <-ch2 {

            return false
        }
    }


    return true

}

func main() {
    isSame := Same(tree.New(1), tree.New(1))    
    if isSame {
        fmt.Println("SAME")
    } else {
        fmt.Println("DIFF")
    }
}
它工作了一次,然后我又运行了一次,它停止了工作……要么就是这样,要么就是我疯了


发生了什么事?

问题是您从未关闭
ch1
,因此您的
for i:=range ch1
循环永远不会结束;它只是读取,直到通道中没有值,然后阻塞。此时,将只有一个goroutine,并且它在侦听空通道时被阻止,因此Go将中止并显示您看到的消息。(类似地,您从不关闭
ch2
,但在您的情况下,这并不重要。如果
ch2
的值小于
ch1
,则会导致死锁。)

老实说,我不确定“围棋之旅”的人到底想了什么解决方案

一个可行但完全是欺骗的选项是硬编码这样一个事实,即您只能看到十个值:

for i := 0; i < 10; i++ {
    if <-ch1 != <-ch2 {
        return false
    }
}
(或者你可以使用一个非匿名函数;称它为
walkAndClose
或其他什么)

顺便提一下,您的
Same
函数假定两棵树的大小相同。如果
t1
有更多的元素,那么
t2
将在末尾隐式填充零(因为

for i := 0; i < 10; i++ {
    if <-ch1 != <-ch2 {
        return false
    }
}
go func() {
    Walk(t1, ch1)
    close(ch1)
}()
for i := range ch1 {
    j, receivedJ := <-ch2
    if i != j || ! receivedJ {
        return false
    }
}
_, receivedJ := <-ch2
if receivedJ {
    return false
}