goroutine 中的 error 不能直接返回给主 goroutine,必须通过 channel(推荐带缓冲)显式传递,多个 goroutine 写入时可避免阻塞或死锁,panic 可用 recover 捕获后发送至 channel。

goroutine 中的 error 不能直接返回给主 goroutine
Go 的 goroutine 是独立执行的,return 只作用于当前 goroutine,主 goroutine 拿不到它的返回值或 panic。常见错误是写成这样:
go func() {
if err := doSomething(); err != nil {
return // 这里 return 完全没用,主 goroutine 不知道出错了
}
}()
必须显式把 error 传出来——最常用、最可控的方式就是通过 channel。
用带缓冲的 channel 收集 error 更安全
多个 goroutine 同时写同一个 error channel,如果 channel 无缓冲且没人及时接收,会阻塞甚至死锁。推荐初始化为带缓冲的 channel,容量等于任务数:
-
errCh := make(chan error, len(tasks))—— 避免 goroutine 因发送失败卡住 - 即使某个任务 panic,也可用
recover捕获并塞进errCh - 主 goroutine 用
for i := 0; i 等待全部结果
不建议用 range 遍历未关闭的 channel,容易提前退出。
立即学习“go语言免费学习笔记(深入)”;
需要区分“单个失败”和“整体失败”的语义
不是所有并发错误都要立刻中止。比如批量发 HTTP 请求,你可能想:收集全部错误再统一处理,而不是一个错就放弃其余。
- 用
errors.Join(err1, err2, ...)(Go 1.20+)合并多个error - 若只要一个错误就判定失败,可在收到第一个非
nilerror后调用cancel()(配合context)停止剩余 goroutine - 注意:
nil不能往chan error发,否则接收端无法区分“成功”和“没发”,应只发非nil错误,或改用chan *error
别忘了 close(channel) 或用 sync.WaitGroup 控制收尾
主 goroutine 不能盲目等 N 次 ,万一某个 goroutine 没启动或 panic 在 send 前,就会永久阻塞。稳妥做法是:
- 用
sync.WaitGroup计数,所有 goroutine 结束后close(errCh),再 range 接收 - 或用
context.WithTimeout包裹整个流程,超时后主动退出等待 - 避免在 goroutine 内部 close channel —— 多个 goroutine close 同一个 channel 会 panic
真正容易被忽略的是:即使所有任务都成功,也要确保 errCh 被正确关闭,否则 range 永远卡住。










