You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言tour.golang树练习:Same函数死锁问题排查求助

解决Go语言树结构对比时的goroutine死锁问题

嘿,我来帮你分析下这个死锁问题的原因,以及怎么修复它。

你的Same函数思路是对的——用Walk把两棵树的节点值发送到channel再对比内容,但出现死锁主要是两个核心问题:

问题原因

  1. Walk函数没有关闭channel
    for c := range ch1这种遍历方式会一直阻塞,直到对应的channel被关闭。如果你的Walk遍历完树之后没关闭channel,goroutine结束后channel处于"未关闭但无发送者"的状态,range循环会永久等待,导致整个程序卡住。

  2. 未处理两棵树节点数量不一致的情况
    假设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)确保了每个Walk goroutine结束后都会关闭对应的channel,接收方不会无限等待。
  • 同时监听两个channel的ok状态,能准确判断节点数量是否一致,避免了因数量不同导致的阻塞。

这样修改后,你的Same函数就能正确判断两棵树是否相同,也不会再出现死锁问题了。

内容的提问来源于stack exchange,提问作者edkeveked

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:08:39