默认会崩溃整个程序;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,但不等于错误被“处理”了——它只是没让程序挂掉。真正的问题在于:错误是否被记录、是否触发重试、是否通知调用方、是否影响后续流程。