go 语言中的三种报错机制

  • 第一种,也就是常说的 error 类型错误,不需要 recover 拯救,处理方式自己决定

  • 第二种,panic 和 recover 是紧密集合的,有点类似 try catch,recover 能捕获到 panic

  • 第三种,一些 Go 语言系统级别的错误,比如发生死锁,数据竞争,这种错误程序会立刻报错,无法 recover

recove 的作用

go 语言中,错误一般会由 error 触发,但是如果比较严重的错误(通常是没有恰当处理的 error,也可是手动触发) 会造成 panic 。 一旦主程序 panic ,会导致整个程序挂掉。如果这个错误不是那么严重,我们希望程序可以继续往下执行,而不是整个程序挂掉。

  1. recover 函数,对 panic 错误进行拦截,避免上传给主函数,进而避免整个程序挂掉。
  2. 可以在程序崩溃前,做一些操作,举个例子,当 web 服务器遇到不可预料的严重问题时,在崩溃前应该将所有的连接关闭,如果不做任何处理,会使得客户端一直处于等待状态。

下面例子

如果给 out 函数传入两个相同的形参,就会引发 panic

如果没有 recover 拦截,fmt.Print 这行是执行不到的。

func main() {
Out(1, 1)
fmt.Println("*******此行函数依然能继续执行******")
}
func Out(numb1, numb2 int) bool {
defer func() {
if r := recover(); r != nil { # 在此处对panic进行拦截,不会将错误继续上报上去。
fmt.Println("异常已扑捉,避免继续往上层传递")
}
}()
if numb1 == numb2 {
panic("两个数不能相等")
}
return numb1 > numb2
}

知识点

  1. recover 仅在延迟函数 defer 中有效
  2. 因为 Go 语言没有异常系统,其使用 panic 触发宕机类似于其他语言的抛出异常,recover 的宕机恢复机制就对应其他语言中的 try/catch 机制。
  3. 谨记一点 recover 只能恢复本协程的 panic

注意:即使是子协程内引发的 panic 依然会导致主程序的挂掉,如下面的例子

func main() {
go OutOne()
go OutTwo()
time.Sleep(time.Minute)
} func OutOne() {
panic("错误")
}
func OutTwo() {
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
fmt.Print("****此处继续执行***")
}
}

进阶

那么上面情况该怎么解决?

其实就是在发生 panic 的协程里面,用 recover 进行拦截。让它传不到主函数。

func main() {
go OutOne()
go OutTwo()
time.Sleep(time.Minute)
} func OutOne() {
defer func() {
if r := recover(); r != nil {
fmt.Println("OutOne 的报错已经别扑捉", r)
}
}()
panic("错误")
}
func OutTwo() {
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
fmt.Println("****此处继续执行***")
}
}

当panic、defer和子函数混合使用时的执行顺序

func f() {
fmt.Println("打开文件b")
defer func() {
fmt.Println("关闭文件b")
}()
panic("文件b读取异常")
} func main() {
fmt.Println("打开文件a")
defer func() { fmt.Println("关闭文件a") }()
f()
fmt.Println("文件正常执行")
} # 输出
打开文件a
打开文件b
关闭文件b
关闭文件a
panic: 文件b读取异常
  • 记住这个例题,当 go 语言发生panic时,会首先执行已经“进栈”的 defer函数,最后然后在报出panic的错误。传给上层的函数。
  • 当子函数发生 panic的时候,函数依然是会先执行已经“进栈”的 defer函数,而爆出 panic

defer

go的代码中,defer 有点类似于压栈操作,只有被执行到了,才会入栈(延迟执行),但是实际上,defer函数是编译过程中,通过调整代码顺序实现

错误日志如何查看

package main

import "log"

func main() {
err := funcA()
if err != nil {
log.Println("日志输出错误")
}
} func funcA() error {
panic("错误")
}

输出:

  • 观察错误输出顺序,错误就是一个入栈的过程,会从底到上的打印,直到遇到 recover
  • 日志能不能输出这条错误,要看这条日志能不能走到。

参考文献

  1. https://www.zhihu.com/question/371695315/answer/1026803101

  2. http://c.biancheng.net/view/64.html

go 语言的宕机恢复(recover)的更多相关文章

  1. Vertica集群单节点宕机恢复方法

    Vertica集群单节点宕机恢复方法 第一种方法: 直接通过admintools -> 5 Restart Vertica on Host 第二种方法: 若第一种方法无法恢复,则清空宕机节点的c ...

  2. mysql group replication 主节点宕机恢复

    一.mysql group replication 生来就要面对两个问题: 一.主节点宕机如何恢复. 二.多数节点离线的情况下.余下节点如何继续承载业务. 在这里我们只讨论第一个问题.也就是说当主结点 ...

  3. Go语言 异常panic和恢复recover用法

    Go语言 异常panic和恢复recover用法 背景:Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在 ...

  4. 存在单点故障的namenode宕机恢复测试

    前提:如果namenode没有做HA,那么至少应该启用secondarynamenode,以便namenode宕机之后手动恢复数据 实验环境:3个节点(cenos 6.10) 测试前数据: 1.为了确 ...

  5. HBase–RegionServer宕机恢复原理

    Region Server宕机总述 HBase一个很大的特色是扩展性极其友好,可以通过简单地加机器实现集群规模的线性扩展,而且机器的配置并不需要太好,通过大量廉价机器代替价格昂贵的高性能机器.但也正因 ...

  6. drbd虚拟机宕机恢复方法

    问题现象 云南计算节点YN-ec-compute-19因系统盘损坏宕机且操作系统无法恢复,其上本地虚拟机无法疏散且无法迁移 拟采用drbd备份的数据对compute19上的虚拟机进行恢复 恢复方法 1 ...

  7. CDH集群主节点宕机恢复

    1       情况概述 公司的开发集群在周末莫名其妙的主节点Hadoop-1的启动固态盘挂了,由于CM.HDFS的NameNode.HBase的Master都安装在Hadoop-1,导致了整个集群都 ...

  8. MySQL - 高可用性:少宕机即高可用?

    我们之前了解了复制.扩展性,接下来就让我们来了解可用性.归根到底,高可用性就意味着 "更少的宕机时间". 老规矩,讨论一个名词,首先要给它下个定义,那么什么是可用性? 1 什么是可 ...

  9. MySQL 系列(四) 主从复制、读写分离、模拟宕机、备份恢复方案生产环境实战

    本章内容: 主从复制 简介原理 备份主库及恢复从库,配置从库生效 读写分离 如果主宕机了,怎么办? 双主的情况 MySQL 备份及恢复方案 备份单个及多个数据库 mysqldump 的常用参数 如何增 ...

  10. HBase RegionServer宕机处理恢复

    本文分析RegionServer宕机后这个region server上的region是如何在其他region server上恢复的. region server宕机后发生了什么   HMaster有一 ...

随机推荐

  1. AEDR8300:光电编码程序构思

    一.实验 1.光电反射理论是经过码盘的window时,电压变低,经过bar时,电压为高,这样可以通过检测到的脉冲数,来进行速度的获取.但是实际并不是这样, 反馈回来的信号是周期性的,经过试验发现,可以 ...

  2. Istio 升级后踩的坑

    背景 前段时间我们将 istio 版本升级到 1.12 后导致现有的应用监控有部分数据丢失(页面上显示不出来). 一个是应用基础信息丢失. 再一个是应用 JVM 数据丢失. 接口维度的监控数据丢失. ...

  3. 滴水 10/13号完成 打印出DOS PE头 节表 开源

    #include<stdio.h> #include<Windows.h> int szie2; #pragma warning(disable : 4996) LPVOID ...

  4. P5491 【模板】二次剩余

    \(\text{Summary}\) 实际上是做法的归纳 一切皆是结论性的,没有证明! 模 \(p\) 意义下的二次剩余有 \(\frac{p-1}2\) 个,二次非剩余也恰有那么多 考虑解关于 \( ...

  5. JZOJ 3184. 【GDOI2013模拟7】最大异或和

    最大异或和 可持久化字典树经典题 题目网上自己找 来波模板 \(Code\) #include<cstdio> #include<iostream> using namespa ...

  6. 组织炎症水平高的RA患者接受TNF拮抗剂治疗的效果更好

    组织炎症水平高的RA患者接受TNF拮抗剂治疗的效果更好van der Pouw Kraan TC, et al. Ann Rheum Dis. 2008;67(4):563-6.目的:不同患者对TNF ...

  7. Oracle中表字段加中文注释,应该怎么写呢?

    首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...

  8. Django中获取用户IP方法

    Django中通过request.META可以来获取用户的IP. request.META 是一个Python字典,包含了所有本次HTTP请求的Header信息,比如用户IP地址和用户Agent(通常 ...

  9. STM32 I2C介绍和软件模拟I2C编程要点

    I2C协议层独特特征: 1. 通过地址(Master/Slave Address)区分不同的设备. 2. ACK信号体制,即通过ACK表示是否进行继续传输. 3.由SCL.SDA的四种关系,映射数据有 ...

  10. javaSE学习一

    java基础 java是一种强类型语言:要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用. java的数据类型有两大类:基本数据类型和引用类型(类.接口.数组) 八大基本数据类型: 1.整 ...