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
相关产品推荐
相关产品推荐

