Panic & recover
如果在匿名函数内panic了,在匿名函数外的defer是否会触发panic-recover?反之在匿名函数外触发panic,是否会触发匿名函数内的panic-recover?
情况 1:匿名函数内的 panic,匿名函数外的 defer-recover 可以捕捉
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in main", r)
}
}()
func() {
panic("panic in anonymous function")
}()
}
// Recovered in main panic in anonymous function
情况 2:匿名函数外的 panic,匿名函数内的 defer-recover 程序崩溃
func main() {
func() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in anonymous function", r)
}
}()
}()
panic("panic in main")
}
// panic: panic in main
// goroutine 1 [running]:
// main.main()
// /Users/alan/github/toy/go/panic_recover/xpanic.go:26 +0x30
结论:
- panic会沿调用栈向上传播
- 只有已经注册的defer函数会在panic时执行
- recover只能在defer函数中直接调用才有效
- recover 只能捕获同一个 goroutine 中的 panic。每个 goroutine 都有自己的调用栈,panic 只会沿着当前 goroutine 的调用栈传播。
- 它保持了 goroutine 之间的独立性,防止一个 goroutine 的问题直接影响其他 goroutine。
- 它简化了并发编程模型,使得每个 goroutine 的行为更加可预测。
- 它鼓励开发者在每个 goroutine 中正确处理错误和异常情况
Golang 有哪些不能recover 的panic
- 运行时错误
- 栈溢出(Stack Overflow)
- OOM
- 并发map写入
- 死锁
- 使用已关闭channel发送接收数据
- 重复panic
- defer 函数中再次panic
- 不同goroutine中发生panic
- recover 只能捕获同一 goroutine 中的 panic。
- 手动调用 os.Exit()
- 系统信号导致panic