Go异常处理机制panic和recover


recover


使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层,直至程序crash。但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的。

func main() {

 print(123)

 print(456)
 panic("throw an error")

 print(678//IDE会有提示: Unreachable code

}

结果:

123456panic: throw an error

goroutine 1 [running]:
main.main()
    /Users/shuangcui/explore/panicandrecover.go:31 +0x67

使用recover()捕获异常:

func main() {

 print(123)

 defer func() {
  if err := recover(); err != nil {
   print("recover it")
  }
 }()

 print(456)
 panic("throw an error")

 print(678//IDE会有提示: Unreachable code

}

结果为:

123456recover it

如果有两个recover,则捕获异常的是后一个

func main() {

 print(123)

 defer func() {
  if err := recover(); err != nil {
   print("recover it")
  }
 }()

 defer func() {
  if err := recover(); err != nil {
   print("复原!")
  }
 }()

 print(456)
 panic("throw an error")

 print(678//IDE会有提示: Unreachable code

}

结果为:

123456复原!

panic之后的任何代码都不会继续执行


前提是panic不在if里面


package main

import "fmt"

func main() {
 defer_call()
 fmt.Println("333 Helloworld")
}

func defer_call() {
 defer func() {
  fmt.Println("11111")
 }()

 defer func() {
  fmt.Println("22222")
 }()

 defer func() {
  if r := recover(); r != nil {
   fmt.Println("Recover from r : ", r)
  }
 }()

 defer func() {
  fmt.Println("33333")
 }()

 fmt.Println("111 Helloworld")

 panic("Panic 1!")


    //使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层, 直至程序crash

    //但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的。

 panic("Panic 2!"//panic1之后的panic2没有任何机会会被执行, panic2之后的任何代码更没有任何机会被执行

 fmt.Println("222 Helloworld")
}

输出为:

111 Helloworld
33333
Recover from r :  Panic 1!
22222
11111
333 Helloworld

对于goroutine中的panic,协程外面的recover是无法恢复的;goroutine中的recover,同样无法恢复协程外的panic


alt

但协程中的recover可以恢复协程中的panic

package main

import (
 "fmt"
 "time"
)

func main() {

 go func() {
  defer func() {
   if err := recover(); err != nil {
    fmt.Println("recover err:", err)
   }
  }()
  panic("里面出错了")
 }()

 //panic("外面出错了")

 time.Sleep(1 * time.Second)

}

输出为:

recover err 里面出错了


主方法中的recover,也可以恢复子方法里的panic


但如果go subfunc(),则同样无法捕获subfunc中的异常

func main() {

 fmt.Println(123)

 defer fmt.Println(999)

 defer func() {
  if err := recover(); err != nil {
   fmt.Println("恢复异常:",err)
  }

 }()
 subfunc()

}

func subfunc() {

 defer fmt.Println(888)
 panic("出现了bug")

 defer fmt.Println(456)

}

结果为:

123
888
恢复异常: 出现了bug
999



因为panic发生的时候,panic函数后面的语句都不会执行了,所以recover函数不能放在panic语句后面执行,而要放在defer函数中执行。

使用 panic 抛出异常后,函数执行将从调用 panic 的地方停止,如果函数内有 defer 调用,则执行 defer 后边的函数调用,如果 defer 调用的函数中没有捕获异常信息,这个异常会沿着函数调用栈往上传递,直到 main 函数仍然没有捕获异常,将会导致程序异常退出


如何区别使用 panic 和 error 两种方式?

惯例是:导致关键流程出现不可修复性错误的使用 panic ,其他使用 error 。

panic 和 recover 的组合有如下特性:

  • 有 panic 没 recover ,程序宕机。
  • 有 panic 也有 recover ,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。



recover能捕获所有错误吗?


不能!

Go 有哪些无法恢复的致命场景?

  • 并发读写 map fatal error: concurrent map read and map write
  • 堆栈内存耗尽(如递归)
runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0200e1bf0 stack=[0xc0200e00000xc0400e0000]
fatal error: stack overflow
  • 将 nil 函数作为 goroutine 启动 fatal error: go of nil func value
  • goroutines 死锁 fatal error: all goroutines are asleep - deadlock!
  • 线程超过设置的最大限制 fatal error: thread exhaustion
  • 超出可用内存 fatal error: runtime: out of memory

总之 都会报fatal error:xxxxxxxx


拓展&参考:

golang panic和recover 实现原理[1]

Go 学习笔记(19)— 函数(05)[如何触发 panic、触发 panic 延迟执行、panic 和 recover 的关系][2]

Go 语言踩坑记——panic 与 recover[3]


参考资料

[1]

golang panic和recover 实现原理: https://blog.csdn.net/u010853261/article/details/102761955

[2]

Go 学习笔记(19)— 函数(05)[如何触发 panic、触发 panic 延迟执行、panic 和 recover 的关系]: https://blog.csdn.net/wohu1104/article/details/105571916

[3]

Go 语言踩坑记——panic 与 recover: https://xiaomi-info.github.io/2020/01/20/go-trample-panic-recover/

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/73484.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue前端 更具router.js 中的meta的roles实现路由卫士,实现权限判断。

参考了之篇文章 1、我在登陆时获取到登录用户的角色名roles,并存入sessionStorage中,具体是在login页面实现,还是在menu页面实现都可以。在menu页面实现,可以显得登陆快一些。 2、编写router.js,注意,一个…

备战2024秋招面试题-最左匹配原则、索引失效情况、算法(最长回文子串)

前言: \textcolor{Green}{前言:} 前言: 💞快秋招了,那么这个专栏就专门来记录一下,同时呢整理一下常见面试题 💞部分题目来自自己的面试题,部分题目来自网络整理 给我冲 学习目标&am…

设计HTML5文档结构

定义清晰、一致的文档结构不仅方便后期维护和拓展,同时也大大降低了CSS和JavaScript的应用难度。为了提高搜索引擎的检索率,适应智能化处理,设计符合语义的结构显得很重要。 1、头部结构 在HTML文档的头部区域,存储着各种网页元…

(十八)大数据实战——Hive的metastore元数据服务安装

前言 Hive的metastore服务作用是为Hive CLI或者Hiveserver2提供元数据访问接口。Hive的metastore 是Hive元数据的存储和管理组件,它负责管理 Hive 表、分区、列等元数据信息。元数据是描述数据的数据,它包含了关于表结构、存储位置、数据类型等信息。本…

财报解读:上半年营收净利双增长,珀莱雅已成为真正的国货之光?

夏季炎热,防晒类产品的销量暴涨。根据千牛数据,防晒衣今年5月全网搜索人数同比增长15%,加购人数同比增长29.8%,访问人数同比增加42%。消费者狂热的防晒需求,孕育着巨大的商机,许多企业开始瞄准这一机会。而…

【MongoDB基础】

目录 一、概述 1.概念 2.相关 2.1 实例 2.2 库 2.3 集合 2.4 文档 2.5 主键 3.特性 4,应用场景 二、安装 1.RPM安装 2.启动数据库 三、目录结构 1.rpm -ql mongodb-org-server 2.rpm -ql mongodb-org-shell 3.rpm -ql mongodb-org-tools 四、默…

【目标检测系列】YOLOV2解读

为更好理解YOLOv2模型,请先移步,了解YOLOv1后才能更好的理解YOLOv2所做的改进。 前情回顾:【目标检测系列】YOLOV1解读_怀逸%的博客-CSDN博客 背景 通用的目标检测应该具备快速、准确且能过识别各种各样的目标的特点。自从引入神经网络以来&a…

深度学习入门

1. 背景 从去年底以来,AIGC 炙手可热,多个业界大佬都认为 AIGC 会给整个产业带来一场革命,甚至所有的软件都会用 AI 重写。从历史上来看,人机交互方式的变革往往会将操作系统带入下一个世代,著名的例子如从命令行界面…

自动化更新导致的各种问题解决办法

由于最近自动化频频更新导致出现各种问题,因此在创建驱动对象代码时改成这种方式 我最近就遇到了由于更新而导致的代码报错,报错信息如下: 复制内容如下: Exception in thread “main” org.openqa.selenium.remote.http.Connecti…

【JavaEE】懒人的福音-MyBatis框架—复杂的操作-动态SQL

【JavaEE】MyBatis框架要点总结(3) 文章目录 【JavaEE】MyBatis框架要点总结(3)1. 多表查询1.1 映射表resultMap1.2 只有部分属性跨表查询1.2.1 依照常规去写代码1.2.2 用标签去实现接口 1.3 分多步的解决方案1.4 与多线程的结合 …

【springboot启动报错】java: 错误: 无效的源发行版:17

报错截图 解决方案 第一步:编辑配置,改为想用的jdk版本 第二步:文件--->项目结构,改为对应的SDK 第三步:文件--->设置--->构建、执行、部署--->编译器--->Java编译器,修改目标字节码版本 第…

c++中的多态

文章目录 1.多态的概念1.1概念 2.多态的定义及实现2.1多态的构成条件2.2虚函数2.3虚函数的重写2.4 C11 override 和 final2.5 重载、覆盖(重写)、隐藏(重定义)的对比 3. 抽象类3.1概念3.2接口继承和实现继承 4.多态的原理4.1虚函数表4.2多态原理分析4.3 动态绑定与静态绑定 5.单…

使用mybatis-plus的updateById方法更新一个numeric(1)类型字段,sql成功执行,但是updates为0,更新失败的解决办法

使用mybatis-plus的updateById方法更新一个numeric(1)类型字段,sql成功执行,但是updates为0,更新失败的解决办法: 背景:我有一张表,有个启用禁用功能,没有放在编辑页面一起编辑保存,…

Vue.js快速入门指南:零基础也能轻松上手,开启前端开发之旅!

目录 MVC设计模式与MVVM设计模式选项式API的编程风格与优势声明式渲染及响应式数据实现原理指令系统与事件方法及传参处理计算属性与侦听器区别与原理条件渲染与列表渲染及注意点class样式与style样式的三种形态表单处理与双向数据绑定原理生命周期钩子函数及原理分析 MVC设计模…

Vscode-工具使用

Vscode ,这玩意儿是开源的,以前用收费的破解版,过段时间就高版本不匹配,这次搞个不要钱的玩玩,记录使用心得 下载 下载地址:官网 点击下载,但是这里有个问题下载比较慢,解决办法&a…

Linux零基础快速入门到精通

一、操作系统概述 二、初始Linux Linux的诞生 Linux内核 Linux发行版 小结 三、虚拟机 认识虚拟机 虚拟化软件及安装 VMware Workstation 17 Pro安装教程https://blog.csdn.net/weixin_62332711/article/details/128695978 远程连接Linux系统 小结 扩展-虚拟机快照 …

python_PyQt5运行股票研究python方法工具V1.0

写在前面: 1 在写研究方法过程中(例如:股票研究),很多方法根据数据的更新需要重复运行获取新的结果,本工具就是固化这些需要重复运行的代码,可以直接在工具中运行得到更新的结果。 2 本文是V1…

Sharding-JDBC概述

前言 ​ 随着业务数据量的增加,原来所有的数据都是在一个数据库上的,网络IO及文件IO都集中在一个数据库上的,因此CPU、内存、文件IO、网络IO都可能会成为系统瓶颈。当业务系统的数据容量接近或超过单台服务器的容量、QPS/TPS接近或超过单个数…

自动方向识别式 LSF型电平转换芯片

大家好,这里是大话硬件。 今天这篇文章想分享一下电平转换芯片相关的内容。 其实在之前的文章分享过一篇关于电平转换芯片的相关内容,具体可以看链接《高速电路逻辑电平转换设计》。当时这篇文章也是分析的电平转换芯片,不过那时候更多的是…

打造企业或者个人IP引流法

打造企业或者个人IP引流法. 大家好,我是百收网SEO编辑:狂潮老师,今天给大家分享企业IP打造的方法 首先我们想让人知道你的企业叫什么,怎么找到你的企业 这个时候我们就需要去各大平台发布信息,客户想了解直接去搜索…