Go语言tour.golang树练习:Same函数死锁问题排查求助
解决Go语言树结构对比时的goroutine死锁问题
嘿,我来帮你分析下这个死锁问题的原因,以及怎么修复它。
你的Same函数思路是对的——用Walk把两棵树的节点值发送到channel再对比内容,但出现死锁主要是两个核心问题:
问题原因
Walk函数没有关闭channelfor c := range ch1这种遍历方式会一直阻塞,直到对应的channel被关闭。如果你的Walk遍历完树之后没关闭channel,goroutine结束后channel处于"未关闭但无发送者"的状态,range循环会永久等待,导致整个程序卡住。未处理两棵树节点数量不一致的情况
假设t1的节点数比t2少,当range ch1遍历完所有数据(如果ch1被关闭的话),此时ch2还有未被接收的数据,发送ch2的goroutine会因为没人接收而阻塞;反过来如果t2节点更少,某次循环中<-ch2会因为ch2没有数据且未关闭而阻塞,最终所有goroutine都进入休眠状态,触发死锁。
修复方案
首先要确保Walk函数遍历完成后关闭channel,然后修改Same函数的逻辑,同时处理两个channel的接收状态:
第一步:修正Walk函数
给Walk添加defer close(ch),保证遍历结束后关闭channel,让接收方知道数据发送完毕:
func Walk(t *tree.Tree, ch chan int) { defer close(ch) // 遍历完成后自动关闭channel var traverse func(*tree.Tree) traverse = func(n *tree.Tree) { if n == nil { return } traverse(n.Left) ch <- n.Value traverse(n.Right) } traverse(t) }
第二步:修改Same函数的对比逻辑
不再依赖range遍历单个channel,而是同时从两个channel接收数据,通过返回的ok标志判断channel是否关闭:
func Same(t1, t2 *tree.Tree) bool { ch1 := make(chan int) ch2 := make(chan int) go Walk(t1, ch1) go Walk(t2, ch2) for { val1, ok1 := <-ch1 val2, ok2 := <-ch2 // 两个channel都关闭,说明所有节点匹配且数量相同 if !ok1 && !ok2 { return true } // 一个关闭一个未关闭,说明节点数量不一致 if ok1 != ok2 { return false } // 节点值不相等 if val1 != val2 { return false } } }
为什么这样能解决问题?
defer close(ch)确保了每个Walkgoroutine结束后都会关闭对应的channel,接收方不会无限等待。- 同时监听两个channel的
ok状态,能准确判断节点数量是否一致,避免了因数量不同导致的阻塞。
这样修改后,你的Same函数就能正确判断两棵树是否相同,也不会再出现死锁问题了。
内容的提问来源于stack exchange,提问作者edkeveked
相关产品推荐
相关产品推荐

