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