贝利信息

如何在Golang中处理并发panic_Golang recover机制安全处理示例

日期:2026-01-04 00:00 / 作者:P粉602998670
recover 只能在引发 panic 的同一 goroutine 的 defer 函数中调用才有效;跨 goroutine 无法捕获,主 goroutine panic 会终止程序,子 goroutine panic 默认静默退出。

Go 的 recover 只能在 defer 中、且必须在引发 panic 的同一 goroutine 内调用才有效——跨 goroutine 的 panic 无法被其他 goroutine 的 recover 捕获。

goroutine 中的 panic 不会自动传播,也不会被外层 recover 拦截

这是最常踩的坑:启动一个新 goroutine 执行可能 panic 的逻辑,却在主 goroutine 里 defer + recover,结果毫无作用。

go func() {
    defer func() {
        if r := recover(); r != nil {
            log.Printf("goroutine recovered: %v", r)
        }
    }()
    panic("boom in goroutine")
}()

使用 defer + recover 封装并发任务的标准写法

安全模式是:每个可能 panic 的 goroutine 自己负责 recover,而不是依赖外部统一捕获。

func safeGo(f func()) {
    go func() {
        defer func() {
            if r := recover(); r != nil {
                log.Printf("panic recovered in goroutine: %v", r)
                // 可选:上报指标、触发告警、写入错误追踪 ID
            }
        }()
        f()
    }()
}

// 使用
safeGo(func() {
    doRiskyWork() // 可能 panic
})

recover 不能恢复所有类型的崩溃

recover 只对 panic 有效,对运行时致命错误(如 nil pointer dereference、stack overflow、out of memory)无效——这些会直接终止程序。

立即学习“go语言免费学习笔记(深入)”;

结合 context 控制并发 goroutine 的生命周期与 panic 后行为

recover 只解决“不崩溃”,但不解决“任务是否完成”“下游是否等待”等问题。真实场景中需配合 context 做协同退出。

func worker(ctx context.Context, ch <-chan int) {
    defer func() {
        if r := recover(); r != nil {
            log.Printf("worker panicked: %v", r)
            // 注意:此处不能直接 return,需确保资源清理
            // 如:close(outChan), mu.Unlock(), file.Close()
        }
    }()
    for {
        select {
        case <-ctx.Done():
            return
        case n := <-ch:
            process(n) // 可能 panic
        }
    }
}

真正难的不是写 recover,而是判断 panic 后的状态是否可信、要不要重试、下游能否容忍部分失败——这些没法靠语法机制自动解决。