为何移除末尾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
相关产品推荐
相关产品推荐

