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

为何移除末尾time.Sleep后Go协程交替打印链表无输出?

问题分析与解决方案

核心问题

你的代码中,worker函数里的break语句仅能跳出当前的select块,无法终止外层的for循环。当处理完最后一个链表节点调用cancel()后,两个worker会陷入无限循环:每次进入select都会命中ctx.Done()分支,执行break跳出select后,又回到for循环的开头,永远无法退出。这导致wg.Wait()一直阻塞,main函数无法正常终止。

虽然fmt.Printf带\n属于行缓冲,理论上会即时输出内容,但程序未终止时,部分终端环境可能不会刷新显示所有输出,或者因为main一直阻塞,你误以为没有打印结果。

修复方案

将worker中的break替换为return(直接退出worker函数),或者使用带标签的break跳出整个for循环,确保worker能正常结束,让wg.Wait()收到信号,main函数顺利终止。

修正后的worker代码示例(使用return)

worker := func(name string, input, output chan *ListNode) {
    wg.Add(1)
    defer wg.Done()
    for {
        select {
        case n := <-input:
            if n == nil {
                return
            }
            fmt.Printf("%s: %d\n", name, n.val)
            if n.next != nil {
                output <- n.next
            } else {
                cancel()
                return
            }
        case <-ctx.Done():
            return
        }
    }
}

或者使用带标签的break:

worker := func(name string, input, output chan *ListNode) {
    wg.Add(1)
    defer wg.Done()
loop:
    for {
        select {
        case n := <-input:
            if n == nil {
                break loop
            }
            fmt.Printf("%s: %d\n", name, n.val)
            if n.next != nil {
                output <- n.next
            } else {
                cancel()
                break loop
            }
        case <-ctx.Done():
            break loop
        }
    }
}

其他说明

  • 移除time.Sleep后,main函数原本依赖短暂延迟让worker完成打印,但这是不可靠的临时方案。
  • 确保worker正常退出才是正确解决思路,这样wg.Wait()能准确等待所有goroutine完成,main函数结束后,终端会完整显示所有打印内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 22:17:37