当心!recover成为”恶魔“--Go中的容错处理进阶

2024-01-16 18:12

本文主要是介绍当心!recover成为”恶魔“--Go中的容错处理进阶,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:

Go语言本身没有try/catch异常机制,因为Go的三位创始人在设计Go语言之出觉得这样写会变得很繁琐。
但因为:Go本身支持函数多返回值,因此在写函数的时候,可以优先考虑容错处理。
接下来,我们来看看在Go语言中如何做容错处理。

一、Go中的容错处理

  • 1、Go语言中没有try/catch异常机制。

  • 2、要实现容错处理:使用error类型即可,默认实现error接口。

type error interface {Error() string
}
  • 3、通过errors.New快速创建error实例。

var xxxError = errors.New("xxxxx") // 快速创建错误类型

4、举一个例子:

我们把之前写的Fibonacci的例子加上容错处理,就变成了下面这样。

函数添加了多返回值,最后一个返回error。
若error有值,说明有异常;
若error无值,说明程序正常。

var LessThanTwoError = errors.New("n shoule not less than 2") // 定义错误类型func GetFibonacci(n int) ([]int, error) {// 容错处理if n <= 2 {return nil, LessThanTwoError}fibList := []int{1, 1}for i := 2; i < n; i++ {fibList = append(fibList, fibList[i-2]+fibList[i-1])}return fibList, nil
}func TestGetFibonacci(t *testing.T) {if value, err := GetFibonacci(0); err != nil {if err == LessThanTwoError {fmt.Println("It is less error.")}t.Error(err)} else {t.Log(value)}
}

代码运行结果如下:

=== RUN   TestGetFibonacci
It is less error.
    recover_test.go:65: n shoule not less than 2
--- FAIL: TestGetFibonacci (0.00s)

FAIL

二、panic、recover、os.Exit

  • panic:用于发送不可恢复的错误,执行defer func内的代码块,并请求退出程序。

  • recover:用于恢复panic抛出的错误。

  • os.Exit:用于直接退出程序。

1、举个panic的例子

func TestPanic(t *testing.T) {defer func() {fmt.Println("Finally!")}()fmt.Println("Test panic is Started.")panic(errors.New("Something wrong!"))
}

测试不通过且抛出异常,输出如下:

=== RUN   TestPanic
Test panic is Started.
Finally!
--- FAIL: TestPanic (0.00s)
panic: Something wrong! [recovered]
    panic: Something wrong!

goroutine 19 [running]:
testing.tRunner.func1.2({0xe195a0, 0xc00008a250})
    D:/Program Files/Go/src/testing/testing.go:1545 +0x238
testing.tRunner.func1()
    D:/Program Files/Go/src/testing/testing.go:1548 +0x397
panic({0xe195a0?, 0xc00008a250?})
    D:/Program Files/Go/src/runtime/panic.go:914 +0x21f
command-line-arguments.TestPanic(0x0?)
    D:/golang/ch14/recover_test.go:26 +0x9d
testing.tRunner(0xc000084820, 0xe47e38)
    D:/Program Files/Go/src/testing/testing.go:1595 +0xff
created by testing.(*T).Run in goroutine 1
    D:/Program Files/Go/src/testing/testing.go:1648 +0x3ad


进程 已完成,退出代码为 1

2、举个os.Exit的例子

其实,os.Exit也可以退出程序。

func TestOsExit(t *testing.T) {fmt.Println("Test os.Exit is Started.")os.Exit(0)
}

输出如下:

=== RUN   TestOsExit
Test os.Exit is Started.
--- FAIL: TestOsExit (0.00s)
panic: unexpected call to os.Exit(0) during test [recovered]
    panic: unexpected call to os.Exit(0) during test

goroutine 6 [running]:
testing.tRunner.func1.2({0x7036a0, 0x75c0a0})
    D:/Program Files/Go/src/testing/testing.go:1545 +0x238
testing.tRunner.func1()
    D:/Program Files/Go/src/testing/testing.go:1548 +0x397
panic({0x7036a0?, 0x75c0a0?})
    D:/Program Files/Go/src/runtime/panic.go:914 +0x21f
os.Exit(0x0)
    D:/Program Files/Go/src/os/proc.go:67 +0x51
command-line-arguments.TestOsExit(0x0?)
    D:/golang/ch14/recover_test.go:42 +0x53
testing.tRunner(0xc000045520, 0x737e78)
    D:/Program Files/Go/src/testing/testing.go:1595 +0xff
created by testing.(*T).Run in goroutine 1
    D:/Program Files/Go/src/testing/testing.go:1648 +0x3ad


进程 已完成,退出代码为 1

3、思考:panicos.Exit究竟有什么区别?

os.Exit退出程序时不会先调用defer func代码块。
os.Exit退出程序时不会输出当前调用栈信息。

4、使用recover举例

那么,如果我们就是想让程序不crash,有没有办法呢?

答案是有的,使用recover,但是很不推荐这么使用recover
因为并没有解决发生panic的问题,只是把错误移除,这样是很不安全的。
甚至,如果是因为系统资源panic,这样我们的服务就变成了僵尸服务,虽然活着但无法提供服务功能。

recover使用方式如下,但一般不推荐使用。

func TestPanicRecover(t *testing.T) {defer func() {if err := recover(); err != nil { // 恢复错误fmt.Println("recover panic", err)}}()fmt.Println("Test panic is Started.")panic(errors.New("Something wrong!"))
}

测试居然通过了,输出如下:

=== RUN   TestPanicRecover
Test panic is Started.
recover panic Something wrong!
--- PASS: TestPanicRecover (0.00s)
PASS

5、必须要小心使用recover

因为使用recover可能会导致:

  1. 形成僵尸服务进程,使安全检查health check失效。

  2. 因为没有crash,导致提供不确定的服务。

所以“Let it Crash!”,让程序异常时通过重启来恢复而不是通过recover跳过异常,往往是我们恢复不确定性错误的最好方法!

这篇关于当心!recover成为”恶魔“--Go中的容错处理进阶的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/613464

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

[MySQL表的增删改查-进阶]

🌈个人主页:努力学编程’ ⛅个人推荐: c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 💻💻💻数据库约束 🔭🔭🔭约束类型 not null: 指示某列不能存储 NULL 值unique: 保证某列的每行必须有唯一的值default: 规定没有给列赋值时的默认值.primary key:

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

从0到1,AI我来了- (7)AI应用-ComfyUI-II(进阶)

上篇comfyUI 入门 ,了解了TA是个啥,这篇,我们通过ComfyUI 及其相关Lora 模型,生成一些更惊艳的图片。这篇主要了解这些内容:         1、哪里获取模型?         2、实践如何画一个美女?         3、附录:               1)相关SD(稳定扩散模型的组成部分)               2)模型放置目录(重要)

go基础知识归纳总结

无缓冲的 channel 和有缓冲的 channel 的区别? 在 Go 语言中,channel 是用来在 goroutines 之间传递数据的主要机制。它们有两种类型:无缓冲的 channel 和有缓冲的 channel。 无缓冲的 channel 行为:无缓冲的 channel 是一种同步的通信方式,发送和接收必须同时发生。如果一个 goroutine 试图通过无缓冲 channel