如果一个 Goroutine 发生了 panic 且没有被 recover 捕获,会导致整个程序崩溃退出
导致整个进程崩溃
如果任何一个子 Goroutine 发生了 panic,且该 Goroutine 内部没有使用 defer + recover 来拦截它,那么整个程序(包括主 Goroutine 和其他所有正在运行的 Goroutine)都会立即终止。
执行 Defer 函数
在 Goroutine 崩溃之前,Go 运行时会按照后进先出(LIFO)的顺序执行该 Goroutine 中所有已注册的 defer 函数。
- 如果在这些
defer函数中调用了recover(),panic 过程会被停止,该 Goroutine 可以继续生存(通常是在defer里处理完后正常退出)。 - 如果没有
recover(),在执行完所有defer后,崩溃会传播到顶层。
无法跨 Goroutine 捕获
你不能在一个 Goroutine 中通过recover捕获另一个 Goroutine 中发生的 panic。
func main() {
// 这种写法无法捕获子 Goroutine 的 panic
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in main")
}
}()
go func() {
panic("panic in child") // 这会导致整个程序崩溃
}()
time.Sleep(time.Second)
}最佳实践建议
为了保证程序的健壮性,通常在创建重要的 Goroutine 时,会在其内部第一行注册一个用于捕获 panic 的 defer 函数:
go func() {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from panic: %v", r)
// 可以在这里进行错误上报或清理工作
}
}()
// 实际业务逻辑
doSomething()
}()总结
- 范围:Panic 的捕获必须在同一个 Goroutine 内进行(隔离性)。
- 后果:若未捕获,会导致整个进程崩溃(全局性)。