Go panic & recover 使用注意点:

简介: Go panic & recover 使用注意点:

 1. panic:

一般表示程序出现了严重故障,此时程序不能继续运行,比如服务挂了...

产生方式/场景

(1) 主动调用:通过 panic() 函数;

(2) 被动调用:panic产生后,会将堆栈信息抛出来,方便定位问题。

例如:程序在运行阶段发生了内存异常操作,例如:空指针的取值索引越界栈溢出改写只读内存... 等等(还有其他情况会导致panic,借鉴简书大佬的链接:Go 常见的引发 panic 的情况

注意点:

1. panic 其实是一个终止函数栈执行的过程,但是在函数退出前都会执行defer里面的函数,直到所有的函数都退出后,才会执行panic

2. recover:

recover是go提供的一个用来截获 panic 信息,重新获取协程控制的函数。


使用要求

1)recover必须在defer函数中使用,但是不能被 defer 直接调用,如:

defer recover() // 直接调用,这样的写法不能恢复panic

2)recover只能恢复同一个协程中的panic,所以必须与可能发生panic的协程在同一个协程中才生效

错误示例:

panic在子协程中,而recover在主协程中,recover不能跨协程捕获panic信息,最终会导致所有的协程全部挂掉,程序会整体退出

package main
import (
  "fmt"
  "runtime/debug"
  "time"
)
// 错误示例:recover不能跨协程捕获panic信息
func Test() {
  panic("Test(): 我异常了...溜了溜了")
}
func main() {
  defer func() {
    err := recover(); if err != nil {
      debug.PrintStack()
      //fmt.Println(string(debug.Stack()))
    }
  }()
  go Test() // recover不能跨协程捕获
  // Test()
  time.Sleep(5 * time.Second) // 模拟执行耗时任务(顺便等待子协程执行)
  fmt.Println("main()不能正常执行...") // panic后,主协程main()无法继续正常执行打印
}

image.gif

错误示例 - 运行结果:

image.gif编辑

正确示例:

package main
import (
  "fmt"
  "runtime/debug"
  "time"
)
// 正确示例:
func Test() {
  defer func() {
    if err := recover(); err != nil {
      debug.PrintStack()
      //fmt.Println(string(debug.Stack()))
    }
  }()
  panic("Test(): 我异常了...溜了溜了")
}
func main() {
  go Test()
  // Test()
  time.Sleep(5 * time.Second)       // 模拟执行耗时任务(顺便等待子协程执行)
  fmt.Println("main()依然是能正常执行的...") // 可以正常打印,即使Test()发生panic
}

image.gif

正确示例 - 运行结果:

image.gif编辑

3. 函数panic后,打印堆栈调用信息:

程序发生panic后,可以将堆栈信息打印出来,方便定位问题:

debug.PrintStack() 或 fmt.Println(string(debug.Stack()))

注意点:

1. 正确使用recover(),要记住recover只能恢复当前协程的panic,否则还是会导致整个进程挂掉

2. recover并非万能的,它只对用户态下的panic关键字有效

实际上在Go语言中,是存在着一些无法恢复的“恐慌”事件的,如fatalthrow方法、fatalpanic方法等,这些都是直接通过调用 exit() 方法进行中断的,属于无法恢复的“恐慌”事件,比如:

对于go1.6以上版本,如果出现 并发map读写 程序会直接以 fatal error 崩溃,即使在同一个协程内有recover()也不能恢复

    • 如果map由多协程同时读和写就会出现 fatal error:concurrent map read and map write 的错误
    • 多个协程同时写会出现 fatal error: concurrent map writes 的错误

                                                                                        写博客是真的...写了好久~

    目录
    相关文章
    |
    3月前
    |
    Go
    实验深度理解Go中try...catch...的panic、defer、recover用法
    文章通过实验代码演示了Go语言中如何使用panic、defer和recover函数来模拟try...catch...的异常处理机制,并详细解释了每个函数的作用和在异常处理中的使用场景。
    32 0
    |
    6月前
    |
    Go 开发者
    Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
    Go语言中的`defer`、`panic`和`recover`提供了一套独特的异常处理方式。`defer`用于延迟函数调用,在返回前执行,常用于资源释放。它遵循后进先出原则。`panic`触发运行时错误,中断函数执行,直到遇到`recover`或程序结束。`recover`在`defer`中捕获`panic`,恢复程序执行。注意避免滥用`defer`影响性能,不应对可处理错误随意使用`panic`,且`recover`不能跨goroutine捕获panic。理解并恰当使用这些机制能提高代码健壮性和稳定性。
    125 2
    |
    6月前
    |
    Go
    Go语言中的异常处理:理解panic与recover
    【2月更文挑战第7天】Go语言虽然以简洁和直接错误处理机制而著称,但它也提供了`panic`和`recover`这两个内置函数来处理程序中的异常情况。本文将深入探讨Go语言中的异常处理机制,包括`panic`和`recover`的使用场景、原理以及最佳实践,帮助读者更好地理解如何在Go中处理异常情况。
    |
    6月前
    |
    网络协议 BI Go
    Go-异常处理(defer recover panic)
    Go-异常处理(defer recover panic)
    71 0
    |
    编译器 Go
    Go学习笔记-defer、panic、recover分析
    Go学习笔记-defer、panic、recover分析
    81 1
    Go学习笔记-defer、panic、recover分析
    |
    11月前
    |
    存储 Cloud Native Go
    Go 语言中 panic 和 recover 搭配使用
    Go 语言中 panic 和 recover 搭配使用
    |
    Go 数据库
    Go语言学习之 panic 和 recover
    Go语言学习之 panic 和 recover
    37 0
    |
    编解码 中间件 Go
    Golang 中比较常见的 panic 异常原因之一
    在 Golang 中,当异常发生时不管是主动触发 panic 还是由于编码错误导致的 panic,我们都可以使用 recover 进行捕获。当时前提必须定义 defer 语句,且 defer 必须放在 panic 之前定义,另外 recover 只有在 defer 调用的函数中才有效。
    1261 0
    Golang 中比较常见的 panic 异常原因之一
    |
    6天前
    |
    安全 网络协议 Go
    Go语言网络编程
    【10月更文挑战第28天】Go语言网络编程
    93 65
    |
    6天前
    |
    网络协议 安全 Go
    Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
    【10月更文挑战第28天】Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
    27 13