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,结果毫无作用。
- 每个 goroutine 有独立的调用栈,panic 只终止当前 goroutine
-
recover()必须出现在 panic 发生的同一个 goroutine 的 defer 函数中 - 主 goroutine panic 会导致整个程序退出;子 goroutine panic 默认静默终止(除非启用了
GODEBUG=panicnil=1等调试标志)
go func() {
defer func() {
if r := recover(); r != nil {
log.Printf("goroutine recovered: %v", r)
}
}()
panic("boom in goroutine")
}()
使用 defer + recover 封装并发任务的标准写法
安全模式是:每个可能 panic 的 goroutine 自己负责 recover,而不是依赖外部统一捕获。
- 避免在匿名 goroutine 外层套 defer —— 那个 defer 属于启动它的 goroutine,不是目标 goroutine
- 把
defer recover逻辑写进 goroutine 内部,或封装为可复用函数如safeGo - recover 后建议记录日志、清理资源(如关闭 channel、释放锁),但不要盲目“吞掉” panic
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语言免费学习笔记(深入)”;
- nil 指针解引用、切片越界、map 写入 nil、channel 关闭 nil 等,在默认配置下会触发 runtime panic,
recover可捕获 - 但若程序因
runtime.SetMaxStack过小导致栈溢出,或 cgo 调用中发生 segfault,则无法 recover -
os.Exit()、syscall.Exit()、向已关闭 channel 发送值(非 panic 场景)等也不受 recover 影响
结合 context 控制并发 goroutine 的生命周期与 panic 后行为
recover 只解决“不崩溃”,但不解决“任务是否完成”“下游是否等待”等问题。真实场景中需配合 context 做协同退出。
- recover 后,若该 goroutine 是某个长任务的一部分,应通过
ctx.Done()通知上游放弃等待 - 不要在 recover 后继续执行可能依赖已破坏状态的逻辑
- 若 goroutine 持有锁或打开文件,recover 后务必显式释放,否则造成泄漏
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 后的状态是否可信、要不要重试、下游能否容忍部分失败——这些没法靠语法机制自动解决。










