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

使用两个Goroutine打印1-100出现死锁,请求错误排查

问题分析与修复

你的代码触发死锁主要有三个核心问题:

1. 变量遮蔽导致全局通道未初始化

你声明了全局变量var my_chan chan int,但在main函数里又用my_chan := make(chan int)重新定义了局部变量——这导致两个worker协程实际调用的是未初始化的全局nil通道。nil通道的读写操作会永久阻塞,这是死锁的根源。

2. WaitGroup的Done调用不匹配

你调用了wg.Add(2),但只有当某个worker处理到number>100时才会调用一次wg.Done(),另一个worker会一直阻塞在number := <-my_chan的读取操作上,永远无法执行wg.Done(),最终wg.Wait()会无限等待,引发死锁。

3. 无缓冲通道的收尾阻塞

当number增加到100时,当前worker打印后number变成101,直接return,没有后续发送操作,但另一个worker还在等待读取通道,主协程也卡在wg.Wait(),所有协程进入休眠状态。


修复后的代码

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func worker(ch chan int) {
    defer wg.Done() // 用defer确保协程退出时必触发Done
    for {
        number, ok := <-ch // 检查通道是否已关闭
        if !ok {
            return
        }
        if number > 100 {
            close(ch) // 关闭通道通知其他worker退出
            return
        }
        fmt.Println(number)
        ch <- number + 1
    }
}

func main() {
    wg.Add(2)
    my_chan := make(chan int)
    go worker(my_chan)
    go worker(my_chan)
    my_chan <- 1

    wg.Wait()
}

修复说明:

  • 去掉全局通道,改为将通道作为参数传递给worker,彻底避免变量遮蔽问题。
  • 用defer wg.Done()确保每个worker无论正常退出还是因通道关闭退出,都会通知WaitGroup,解决Done调用不匹配的问题。
  • 当number超过100时关闭通道,让另一个worker通过ok值判断通道状态,正常退出循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:54:24