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

Golang Channel未关闭致指定打印语句未执行,求排查错误原因

问题分析与修复

你的代码里有几个核心问题导致打印语句无法执行,以及程序可能陷入阻塞:

1. 无缓冲Channel的发送阻塞

orderCh和transaksiCh是无缓冲Channel,当工作goroutine执行到orderCh <- orderResp或transaksiCh <- transaksiResp时,会因为没有对应的接收操作而直接阻塞——此时主goroutine还在遍历errCh,根本没到接收数据Channel的步骤。这会导致工作goroutine卡在发送步骤,无法继续执行后续的打印语句和wg.Done()。

2. errCh遍历阻塞

主goroutine的for err := range errCh循环,在取完errCh里的2个错误后,会因为errCh未关闭而一直阻塞(负责关闭errCh的goroutine因为wg.Wait()没完成而卡住),永远无法进入后续的select逻辑。

3. select逻辑缺陷

即使前面的阻塞解决了,当前的select只会接收其中一个Channel的数据,另一个Channel的发送依然会阻塞,导致对应的工作goroutine无法完成。


修复后的代码

func (u *Usecase) GetOrderDetailByIDUsecase(ctx context.Context, orderId uint64) (*order.OrderPageDetailResponseDTO, error) {
    var wg sync.WaitGroup
    // 给数据Channel设置缓冲容量1,避免发送阻塞
    orderCh := make(chan *order.OrderResponseDTO, 1)
    transaksiCh := make(chan *transaksi.TransaksiResponseDTO, 1)
    errCh := make(chan error, 2)

    wg.Add(1)
    go func() {
        defer wg.Done() // 用defer确保WaitGroup计数一定会减少
        fmt.Println("order start")
        orderResp, err := u.orderController.GetOrderByID(ctx, orderId)
        fmt.Println("order done")
        errCh <- err
        orderCh <- orderResp
        fmt.Println("order finally done") // 原代码此处拼写错误,已修正
    }()

    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Println("transaksi start")
        transaksiResp, err := u.transaksiController.GetTransaksiByID(ctx, int64(orderId))
        fmt.Println("transaksi done")
        errCh <- err
        transaksiCh <- transaksiResp
        fmt.Println("transaksi finally done")
    }()

    go func() {
        wg.Wait()
        close(errCh)
        close(orderCh)
        close(transaksiCh)
    }()
    
    // 收集所有错误
    var errs []error
    for err := range errCh {
        if err != nil {
            errs = append(errs, err)
        }
    }
    if len(errs) > 0 {
        return nil, errs[0] // 可根据需求合并多个错误
    }

    // 直接读取数据,Channel已关闭,不会阻塞
    orderResp := <-orderCh
    transaksiResp := <-transaksiCh

    return &order.OrderPageDetailResponseDTO{
        Order:     orderResp,
        Transaksi: transaksiResp,
    }, nil
}

关键修复点

  • 给orderCh和transaksiCh添加缓冲容量1,让发送操作不会阻塞,工作goroutine能顺利执行到打印语句。
  • 使用defer wg.Done(),确保即使goroutine内部出现异常,也能正确减少WaitGroup计数。
  • 调整数据接收逻辑:因为WaitGroup已确保两个goroutine完成,直接从关闭的Channel读取数据即可,无需select。
  • 修正了第一个goroutine里的打印语句拼写错误(原代码写的是transaksi finaly done,应为order finally done)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:00:09