默认会崩溃整个程序;goroutine 中未捕获的 panic 仅终止该 goroutine,需在内部用 defer/recover 捕获,recover 对其他 goroutine 无效,推荐用 errgroup.Group 统一管理并发错误。

goroutine 中 panic 会崩溃整个程序吗
默认会。启动的 goroutine 如果发生未捕获的 panic,不会传播到主 goroutine,但会导致该 goroutine 消失,且无法被上层感知——这看起来像“静默失败”,实际是资源泄漏和逻辑断裂的隐患。
- 必须在每个独立 goroutine 内部用
defer/recover捕获 panic,否则错误丢失 -
recover()只在defer函数中有效,且仅对当前 goroutine 的 panic 生效 - 不要依赖主 goroutine 的 recover 拦截子 goroutine 的 panic —— 它根本收不到
使用 errgroup.Group 等待并发任务并收集错误
errgroup.Group 是标准库 golang.org/x/sync/errgroup 提供的轻量工具,能自然等待所有 goroutine 结束,并返回首个非 nil 错误(或 nil)。
- 调用
eg.Go(func() error { ... })启动任务,函数签名必须返回error -
eg.Wait()阻塞直到全部完成,返回第一个触发的error;若需收集全部错误,得自己维护[]error切片 - 注意:一旦某个任务返回非 nil error,
eg.Wait()不会自动取消其余任务(除非启用WithContext)
eg, ctx := errgroup.WithContext(context.Background())
for i := range tasks {
i := i // 避免闭包变量复用
eg.Go(func() error {
select {
case <-ctx.Done():
return ctx.Err()
default:
return processTask(tasks[i])
}
})
}
if err := eg.Wait(); err != nil {
log.Printf("at least one task failed: %v", err)
}
channel + select 处理多个 goroutine 的错误传递
当需要细粒度控制错误类型、区分成功/失败数量,或配合超时/取消时,手动用 chan error 更灵活。
- 为每个 goroutine 分配独立的
errCh chan,避免多个 goroutine 写同一 channel 导致 panic - 用
select配合context.Done()实现可取消的等待,防止某任务卡死拖垮整体 - 注意关闭 channel 的时机:应在所有发送者退出后由 sender 或专用 goroutine 关闭,receiver 用
range安全读取
为什么不能只靠 defer recover 就算完事
recover 能止住 panic,但不等于错误被“处理”了——它只是没让程序挂掉。真正的问题在于:错误是否被记录、是否触发重试、是否通知调用方、是否影响后续流程。
立即学习“go语言免费学习笔记(深入)”;
- recover 后若忽略 error 值,等于把 panic 当成普通日志,掩盖了真实故障点
- 在 HTTP handler 或定时任务中,recover 住 panic 却不返回响应或不标记失败,下游会认为操作成功
- 并发场景下,多个 goroutine 同时 panic 并 recover,若共用日志对象或计数器,可能引发竞态,需加锁或用原子操作
错误管理的难点从来不在“怎么不让程序崩”,而在于“崩之前,你有没有拿到足够信息去诊断和修复”。并发放大了这个挑战——每个 goroutine 都是独立的错误上下文。











