recover 只对当前 goroutine 有效,必须在 defer 中调用;子 goroutine panic 不会影响主 goroutine,需各自独立 defer+recover 处理,并通过 channel 和 WaitGroup 传递错误。

recover 在 goroutine 中根本捕获不到 panic
Go 的 recover 只对**当前 goroutine** 中的 panic 有效,且必须在 defer 函数中调用。如果你在主 goroutine 启动多个子 goroutine,并期望用主 goroutine 的 recover 捕获子 goroutine 的 panic,那注定失败——子 goroutine 崩溃时主 goroutine 完全无感,程序也不会退出(除非所有 goroutine 都退出且 main 返回)。
常见错误现象:panic: runtime error: index out of range 发生在某个 worker goroutine 里,但主程序照常运行、无日志、无提示、任务“静默丢失”。
- 每个可能 panic 的 goroutine 必须**自己配
defer + recover** - 不能依赖外层函数或主 goroutine 的
recover -
recover()返回nil表示当前 goroutine 没有 panic 正在发生,不是“捕获失败”,而是压根没触发
标准 recover 模式:defer 中调用并检查返回值
在并发任务函数内部,defer 是唯一能稳定包裹 recover 的时机。注意:必须在 defer 的匿名函数里调用 recover(),且不能提前 return 或被其他逻辑干扰。
func doTask(id int, data []string) {
defer func() {
if r := recover(); r != nil {
log.Printf("task %d panicked: %v", id, r)
// 这里可上报、记录、标记失败等
}
}()
// 实际业务逻辑,可能 panic
_ = data[100] // 触发 panic
}- 不要写成
defer recover()—— 这会立即执行,返回nil - 不要在
defer外判断recover() != nil—— 语法错误,recover只在 defer 中有效 - 如果任务需返回结果,recover 后建议设默认值或走错误通道,避免调用方收到未初始化的变量
配合 channel 和 WaitGroup 实现带错误反馈的并发控制
单纯 recover 只能防崩溃,无法把错误传递给调度方。真实场景中,你需要知道“哪个任务失败了、为什么失败”。推荐用 chan error 收集错误,配合 sync.WaitGroup 等待全部完成。
三层自动备份:每日时间戳快照、次级硬盘镜像、紧急对话导出。
立即学习“go语言免费学习笔记(深入)”;
func runTasks(tasks []func() error, workers int) []error {
errCh := make(chan error, len(tasks))
var wg sync.WaitGroup
<pre class="brush:php;toolbar:false;">for _, task := range tasks {
wg.Add(1)
go func(t func() error) {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
errCh <- fmt.Errorf("panic: %v", r)
}
}()
if err := t(); err != nil {
errCh <- err
}
}(task)
}
go func() {
wg.Wait()
close(errCh)
}()
var errors []error
for err := range errCh {
errors = append(errors, err)
}
return errors}
- channel 缓冲区大小设为
len(tasks)避免因未及时读取导致 goroutine 阻塞在发送上 - 务必在
go func内部调用wg.Done(),且放在defer最前,确保 panic 时也能计数减一 - 不要在 recover 后继续执行后续业务逻辑——状态已不可信,应直接退出该 goroutine
recover 不是错误处理替代品,慎用于非致命场景
recover 应只用于处理**本可预判但难以完全规避的运行时异常**,比如第三方库 panic、反射调用失败、JSON 解析中结构体字段类型突变等。它不适用于业务校验失败(如参数为空、权限不足),这类情况该用 error 显式返回。
- 频繁依赖 recover 捕获
nil pointer dereference,说明代码缺少空值检查,属于 bug 而非异常 - recover 后若继续往数据库写脏数据、发重复消息,问题比 panic 更严重
- 在 HTTP handler 或 gRPC 方法里 recover 是常见做法,但目的应是防止服务整体挂掉,同时记录 panic 上下文,而非掩盖逻辑缺陷
真正难处理的是 recover 后的状态一致性——goroutine 可能已部分修改全局变量、缓存或文件,这些副作用无法回滚。这时候与其花力气 recover,不如从设计上减少共享状态、用不可变数据或事务边界隔离风险。

















