当前位置:首页 > 科技  > 软件

Go 语言中 panic 和 recover 搭配使用

来源: 责编: 时间:2023-10-10 18:32:17 389观看
导读本次主要聊聊 Go 语言中关于 panic 和 recover 搭配使用 ,以及 panic 的基本原理最近工作中审查代码的时候发现一段代码,类似于如下这样,将 recover 放到一个子协程里面,期望去捕获主协程的程序异常图片看到此处,是否会想

本次主要聊聊 Go 语言中关于 panic 和 recover 搭配使用 ,以及 panic 的基本原理d5P28资讯网——每日最新资讯28at.com

最近工作中审查代码的时候发现一段代码,类似于如下这样,将 recover 放到一个子协程里面,期望去捕获主协程的程序异常d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

看到此处,是否会想这段代码在项目中是想当然写出来的吧,然而平日中,大多问题是出现在认知偏差上,那么本次,我们就来消除一下这个认知偏差d5P28资讯网——每日最新资讯28at.com

关于 Go 语言中显示的使用 panic 的地方不多,一般 panic ,基本上会出现在咱们程序出现异常退出的时候d5P28资讯网——每日最新资讯28at.com

例如访问了空指针里面的值,则会 panic 报错无效的内存地址,又例如访问量数组中不存在的数组所索引,或者切片索引,那么会报错 panic 数组越界等等d5P28资讯网——每日最新资讯28at.com

可是碰到这些 panic 的时候,实际上我们并不期望当前的服务直接挂掉,而是期望这个异常能够被识别,且不影响程序其他部分的模块运行d5P28资讯网——每日最新资讯28at.com

正常捕获异常

在 Go 中可以将 defer 和 recover 进行搭配使用,可以捕获和处理大部分的异常情况,例如可以这样d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

这里可以看到,recover 捕获异常和发生异常的部分是在同一个协程中,实验证明是可以正常捕获并且处理异常d5P28资讯网——每日最新资讯28at.com

并没有捕获到异常

  1. 直接不做显示的 recover,自然 panic 程序崩溃会如期而至,此处我们显示的使用 panic 函数来制造恐慌
func main() {   log.SetFlags(log.Lshortfile)   panic("panic coming...")}

图片图片d5P28资讯网——每日最新资讯28at.com

  1. 不使用 defer 来进行处理
func main() {   log.SetFlags(log.Lshortfile)    if err := recover(); err != nil {     log.Println("recover panic : ", err)    }   panic("panic coming...")}

图片图片d5P28资讯网——每日最新资讯28at.com

自然 recover 函数是在 panic 调用之前就已经执行,此时是还没有异常需要捕获和恢复的,待程序运行到 panic 处的时候,实际上并没有没有处理程序崩溃的异常d5P28资讯网——每日最新资讯28at.com

结果,仍然是程序崩溃d5P28资讯网——每日最新资讯28at.com

  1. 当然,还有文章开头提到的出现 panic 的位置和捕获和处理程序崩溃异常的位置不在同一个协程,自然也是没法捕获到的,这一点需要注意,其他的语言可能不是这样,但是 Go 中是这样的

panic 基本原理

看了上述现象,实际上还是对知识点理解得不够,使用的时候想当然了,就像使用 defer 一样,如果对他不够了解的话,使用的时候,确实会出现一些奇奇怪怪的现象,对于 defer 的使用可以查看文末的文章地址d5P28资讯网——每日最新资讯28at.com

  1. panic 函数和 recover 函数,Go 源码builtin/builtin.go中可以看到注释

图片图片d5P28资讯网——每日最新资讯28at.com

注释中有说关于 panic 和 recover 的使用是作用于当前协程的,因此我们使用的时候,如果跨协程教程使用,自然不会达到我们期望的效果d5P28资讯网——每日最新资讯28at.com

  1. 继续查看关于 panic 的源码,实际上是一个结构,放到 defer 结构里面的一个指针,源码位置:runtime/runtime2.go

图片图片d5P28资讯网——每日最新资讯28at.com

_panic 的结构如下:d5P28资讯网——每日最新资讯28at.com

type _panic struct {   argp      unsafe.Pointer   arg       interface{}   link      *_panic   pc        uintptr   sp        unsafe.Pointer   recovered bool   aborted   bool   goexit    bool}

上述两个结构表达的意思是,程序中出现 panic 的时候,实际上都会创建一个 _panic 结构,这个 _panic 结构里面存储了当前程序崩溃的一些必要信息,如下:d5P28资讯网——每日最新资讯28at.com

  1. argp

是一个 unsafe.Pointer 类型的成员,指向 defer 调用参数的指针d5P28资讯网——每日最新资讯28at.com

  1. arg

出现 panic 的原因,如果我们显示调用 panic,那么就是我们填入 panic 函数中的参数,例如上述的 panic coming ...d5P28资讯网——每日最新资讯28at.com

  1. link

是一个指针,指向上一个,最近的一个 _panic 结构的地址,实际上此处就可以看到这个指针对应的是一个链表,一个又多个 _panic 结构组成的链表d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

程序运行的时候可以执行 go tool compile -S main.god5P28资讯网——每日最新资讯28at.com

可以看到汇编代码,可能其他的看不懂,但是我们可以看到如下关键词d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

  • log.(*Logger).SetFlags(SB) 即是执行到我们调用 log 去设置参数
  • 程序走到 panic 函数的时候,实际上是执行了 runtime.gopanic 函数,我们一起看看源码

图片图片d5P28资讯网——每日最新资讯28at.com

代码中可以看到 p.recovered 逻辑下的关于 recover 的逻辑被删除掉了,在文章的后面会继续说到,当前我们先关注 panic 的事项d5P28资讯网——每日最新资讯28at.com

runtime.gopanic 程序的逻辑大体是这样的d5P28资讯网——每日最新资讯28at.com

  1. 获取当前 协程 的指针
  2. 初始化一个 _panic 结构 p,并将当前协程上对应的数据赋值给到 p 上,且将 当前协程 _panic 挂到 link 上
  3. 进入循环后,拿到当前协程的 _defer 数据
  4. 查看 _defer 指针数据 中是否有 defer 调用,如果有则执行
  5. 处理完基本逻辑之后,打印 panic 信息,例如我们 demo 中的 panic coming ... 信息
  6. 最终退出程序

Xdm 可以看上图,自己捋一捋逻辑就清晰了d5P28资讯网——每日最新资讯28at.com

接着,我们来看d5P28资讯网——每日最新资讯28at.com

fatalpanic

图片图片d5P28资讯网——每日最新资讯28at.com

通过 runtime.gopanic 我们可以看到 fatalpanic 函数基本上就是做一个收尾工作了,如果上述程序处理完毕之后, fatalpanic 校验到 panic 是需要 recover 的,那么就打印 [recovered]d5P28资讯网——每日最新资讯28at.com

打印的这个信息是由 上图中 printpanics 完成的d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

这下知道 panic 是如何去执行的了,那么对于现在来研究 recover 是如何落实的d5P28资讯网——每日最新资讯28at.com

recover

还是同一个例子,咱们将 defer 部分的代码注打开,来继续看看效果d5P28资讯网——每日最新资讯28at.com

func main() {   log.SetFlags(log.Lshortfile)   defer func() {      if err := recover(); err != nil {         log.Println("recover panic : ", err)      }   }()   panic("panic coming...")}

自然效果是我们期望的,捕获到了异常,且处理了d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

继续打印汇编来查看一下关键词,是否有我们期望的函数出现d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

此处我们可以看到,实际 Go 中调用了多个函数d5P28资讯网——每日最新资讯28at.com

  1. runtime.gorecover
  2. main.main.opendefer
  3. log.(*Logger).SetFlags
  4. runtime.gopanic
  5. runtime.deferreturn

自然明眼人都看的出现,关键的函数实现自然是 runtime.gorecover ,那么我们来一探究竟d5P28资讯网——每日最新资讯28at.com

runtime.gorecover

图片图片d5P28资讯网——每日最新资讯28at.com

查看源码我们可以知道, runtime.gorecover 实际上就是根据当前协程的 _panic 结构数据来判断是否需要恢复,如果需要则将 p.recovered = trued5P28资讯网——每日最新资讯28at.com

自然在这里将当前协程的数据修改掉,正是为了后续执行 runtime.gopanic 的时候提供保障, runtime.gopanic 执行的时候就会去判断和处理这个 p.recoveredd5P28资讯网——每日最新资讯28at.com

前文中提到的关于 runtime.gopanic 中 处理 p.recovered 的逻辑是这样的d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

图片图片d5P28资讯网——每日最新资讯28at.com

  1. 如上可以看到 runtime.gorecover 去对 p.recovered 设置是否恢复
  2. runtime.gopanic 中校验 p.recovered 已处理,则执行 recovery 函数
  3. recovery 函数中去处理对应的寄存器的值去维护上下文
  4. 最后我们可以看到最终调用 gogo 函数跳回原来调用的位置

因此,当我们在同一个协程中出现了 panic,且在同一个协程中去使用 defer 来配合 recover 来进行捕获异常和处理异常,就可以得以实现,看到这里,有没有觉得还是蛮简单的,不就是去对一个 p.recovered 进行配合处理吗d5P28资讯网——每日最新资讯28at.com

自然,表面上是这样,其中对于寄存器的各种数据处理涉及的内容还是不少的,不过这不在我们今天聊的范畴中了d5P28资讯网——每日最新资讯28at.com

总结

至此,相信你已经知道了这些d5P28资讯网——每日最新资讯28at.com

  1. 为什么 panic 和 defer ,recover 配合使用的时候要在同一个协程中了吧
  2. 相信你还知道了 panic 和 recover 的处理流程

本文链接:http://www.28at.com/showinfo-26-12749-0.htmlGo 语言中 panic 和 recover 搭配使用

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Springboot整合Hutool自定义注解实现数据脱敏

下一篇: 聊聊C#归并排序算法

标签:
  • 热门焦点
  • 官方承诺:K60至尊版将会首批升级MIUI 15

    全新的MIUI 15今天也有了消息,在官宣了K60至尊版将会搭载天玑9200+处理器和独显芯片X7的同时,Redmi给出了官方承诺,K60至尊重大更新首批升级,会首批推送MIUI 15。也就是说虽然
  • 7月安卓手机性能榜:红魔8S Pro再夺榜首

    7月份的手机市场风平浪静,除了红魔和努比亚带来了两款搭载骁龙8Gen2领先版处理器的新机之外,别的也想不到有什么新品了,这也正常,通常6月7月都是手机厂商修整的时间,进入8月份之
  • 轿车从天而降电动车主被撞身亡 超速抢道所致:现场视频让网友吵翻

    近日,上海青浦区法院判决轿车从天而降电动车主被撞身亡案,轿车车主被判有期徒刑一年。案件显示当时男子驾驶轿车在上海某路段行驶,前车忽然转弯提速超车,
  • 把LangChain跑起来的三个方法

    使用LangChain开发LLM应用时,需要机器进行GLM部署,好多同学第一步就被劝退了,那么如何绕过这个步骤先学习LLM模型的应用,对Langchain进行快速上手?本片讲解3个把LangChain跑起来
  • 分享六款相见恨晚的PPT模版网站, 祝你做出精美的PPT!

    1、OfficePLUSOfficePLUS网站旨在为全球Office用户提供丰富的高品质原创PPT模板、实用文档、数据图表及个性化定制服务。优点:OfficePLUS是微软官方网站,囊括PPT模板、Word模
  • JavaScript学习 -AES加密算法

    引言在当今数字化时代,前端应用程序扮演着重要角色,用户的敏感数据经常在前端进行加密和解密操作。然而,这样的操作在网络传输和存储中可能会受到恶意攻击的威胁。为了确保数据
  • 冯提莫签约抖音公会 前“斗鱼一姐”消失在直播间

    来源:直播观察提起“冯提莫”这个名字,很多网友或许听过,但应该不记得她是哪位主播了。其实,作为曾经的“斗鱼一姐”,冯提莫在游戏直播的年代影响力不输于现
  • iQOO Neo8 Pro抢先上架:首发天玑9200+ 安卓性能之王

    经过了一段时间的密集爆料,昨日iQOO官方如期对外宣布:将于5月23日推出全新的iQOO Neo8系列新品,官方称这是一款拥有旗舰级性能调校的作品。随着发布时
  • SN570 NVMe SSD固态硬盘 价格与性能兼具

    SN570 NVMe SSD固态硬盘是西部数据发布的最新一代WD Blue系列的固态硬盘,不仅闪存技术更为精进,性能也得到了进一步的跃升。WD Blue SN570 NVMe SSD的包装外
Top