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 的错误

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

    目录
    相关文章
    实验深度理解Go中try...catch...的panic、defer、recover用法
    文章通过实验代码演示了Go语言中如何使用panic、defer和recover函数来模拟try...catch...的异常处理机制,并详细解释了每个函数的作用和在异常处理中的使用场景。
    147 0
    |
    Go 开发者
    Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
    Go语言中的`defer`、`panic`和`recover`提供了一套独特的异常处理方式。`defer`用于延迟函数调用,在返回前执行,常用于资源释放。它遵循后进先出原则。`panic`触发运行时错误,中断函数执行,直到遇到`recover`或程序结束。`recover`在`defer`中捕获`panic`,恢复程序执行。注意避免滥用`defer`影响性能,不应对可处理错误随意使用`panic`,且`recover`不能跨goroutine捕获panic。理解并恰当使用这些机制能提高代码健壮性和稳定性。
    375 2
    Go语言中的异常处理:理解panic与recover
    【2月更文挑战第7天】Go语言虽然以简洁和直接错误处理机制而著称,但它也提供了`panic`和`recover`这两个内置函数来处理程序中的异常情况。本文将深入探讨Go语言中的异常处理机制,包括`panic`和`recover`的使用场景、原理以及最佳实践,帮助读者更好地理解如何在Go中处理异常情况。
    |
    编译器 Go
    Go学习笔记-defer、panic、recover分析
    Go学习笔记-defer、panic、recover分析
    160 1
    Go学习笔记-defer、panic、recover分析
    |
    网络协议 BI Go
    Go-异常处理(defer recover panic)
    Go-异常处理(defer recover panic)
    132 0
    |
    存储 Cloud Native Go
    Go 语言中 panic 和 recover 搭配使用
    Go 语言中 panic 和 recover 搭配使用
    131 0
    |
    Go 数据库
    Go语言学习之 panic 和 recover
    Go语言学习之 panic 和 recover
    95 0
    |
    7月前
    |
    编译器 Go
    揭秘 Go 语言中空结构体的强大用法
    Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
    |
    7月前
    |
    运维 监控 算法
    监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
    在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
    |
    1月前
    |
    数据采集 Go API
    Go语言实战案例:多协程并发下载网页内容
    本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。