0

0

记录Golang Recover的一个小坑

藏色散人

藏色散人

发布时间:2020-12-22 15:56:50

|

3928人浏览过

|

来源于learnku

转载

下面由golang教程栏目给大家介绍Golang Recover的一个小坑,希望对需要的朋友有所帮助!

记录Golang Recover的一个小坑

1.error

Golang被诟病非常多的一点就是缺少强大方便的异常处理机制,大部分高级编程语言,比如Java、PHP、Python等都拥有一种try catch机制,这种异常捕获机制可以非常方便的处理程序运行中可能出现的各种意外情况。

严格来说,在Go里面,错误和异常是2种不同的类型,错误一般是指程序产生的逻辑错误,或者意料之中的意外情况,而且异常一般就是panic,比如角标越界、段错误。

对于错误,Golang采用了一种非常原始的手段,我们必须手动处理可能产生的每一个错误,一般会把错误返回给调用方,下面这种写法在Go里面十分常见:

package mainimport (
    "errors"
    "fmt")func main() {
    s, err := say()
    if err != nil {
        fmt.Printf("%s\n", err.Error())
    } else {
        fmt.Printf("%s\n", s)
    }}func say() (string, error) {
    // do something
    return "", errors.New("something error")}复制代码

这种写法最大的问题就是每一个error都需要判断处理,非常繁琐,如果使用try catch机制,我们就可以统一针对多个函数调用可能产生的错误做处理,节省一点代码和时间。不过咱们今天不是来讨论Go的异常错误处理机制的,这里只是简单说一下。

立即学习go语言免费学习笔记(深入)”;

2.panic

一般错误都是显示的,程序明确返回的,而异常往往是隐示的,不可预测的,比如下面的代码:

package mainimport "fmt"func main() {
    fmt.Printf("%d\n", cal(1,2))
    fmt.Printf("%d\n", cal(5,2))
    fmt.Printf("%d\n", cal(5,0)) //panic: runtime error: integer pide by zero 
    fmt.Printf("%d\n", cal(9,5))}func cal(a, b int) int {
    return a / b}复制代码

在执行第三个计算的时候会发生一个panic,这种错误会导致程序退出,下面的代码的就无法执行了。当然你可以说这种错误理论上是可以预测的,我们只要在cal函数内部做好处理就行了。

然而实际开发中,会发生panic的地方可能特别多,而且不是这种一眼就能看出来的,在Web服务中,这样的panic会导致整个Web服务挂掉,特别危险。

3.recover

虽然没有try catch机制,Go其实有一种类似的recover机制,功能弱了点,用法很简单:

package mainimport "fmt"func main() {
    fmt.Printf("%d\n", cal(1, 2))
    fmt.Printf("%d\n", cal(5, 2))
    fmt.Printf("%d\n", cal(5, 0))
    fmt.Printf("%d\n", cal(9, 2))}func cal(a, b int) int {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("%s\n", err)
        }
    }()
    return a / b}复制代码

首先,大家得理解defer的作用,简单说defer就类似于面向对象里面的析构函数,在这个函数终止的时候会执行,即使是panic导致的终止。

所以,在cal函数里面每次终止的时候都会检查有没有异常产生,如果产生了我们可以处理,比如说记录日志,这样程序还可以继续执行下去。

WeWedding婚纱影楼小程序
WeWedding婚纱影楼小程序

婚纱影楼小程序提供了一个连接用户与影楼的平台,相当于影楼在微信的官网。它能帮助影楼展示拍摄实力,记录访客数据,宣传优惠活动。使用频率高,方便传播,是影楼在微信端宣传营销的得力助手。功能特点:样片页是影楼展示优秀摄影样片提供给用户欣赏并且吸引客户的。套系页是影楼根据市场需求推出的不同套餐,用户可以按照自己的喜好预定套系。个人中心可以查看用户预约的拍摄计划,也可以获取到影楼的联系方式。

下载

4.注意的坑

一般defer recover这种机制经常用在常驻进程的应用,比如Web服务,在Go里面,每一个Web请求都会分配一个goroutine去处理,在没有做任何处理的情况下,假如某一个请求发生了panic,就会导致整个服务挂掉,这是不可接受的,所以在Web应用里面必须使用recover保证即使某一个请求发生错误也不影响其它请求。

这里我使用一小段代码模拟一下:

package mainimport (
    "fmt")func main() {
    requests := []int{12, 2, 3, 41, 5, 6, 1, 12, 3, 4, 2, 31}
    for n := range requests {
        go run(n) //开启多个协程
    }

    for {
        select {}
    }}func run(num int) {
    //模拟请求错误
    if num%5 == 0 {
        panic("请求出错")
    }
    fmt.Printf("%d\n", num)}复制代码

上面这段代码无法完整执行下去,因为其中某一个协程必然会发生panic,从而导致整个应用挂掉,其它协程也停止执行。

解决方法和上面一样,我们只需要在run函数里面加入defer recover,整个程序就会非常健壮,即使发生panic,也会完整的执行下去。

func run(num int) {
    defer func() {
        if err := recover();err != nil {
            fmt.Printf("%s\n", err)
        }
    }()
    if num%5 == 0 {
        panic("请求出错")
    }
    fmt.Printf("%d\n", num)}复制代码

上面的代码只是演示,真正的坑是:如果你在run函数里面又启动了其它协程,这个协程发生的panic是无法被recover的,还是会导致整个进程挂掉,我们改造了一下上面的例子:

func run(num int) {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("%s\n", err)
        }
    }()
    if num%5 == 0 {
        panic("请求出错")
    }
    go myPrint(num)}func myPrint(num int) {
    if num%4 == 0 {
        panic("请求又出错了")
    }
    fmt.Printf("%d\n", num)}复制代码

我在run函数里面又通过协程的方式调用了另一个函数,而这个函数也会发生panic,你会发现整个程序也挂了,即使run函数有recover也没有任何作用,这意味着我们还需要在myPrint函数里面加入recover。但是如果你不使用协程的方式调用myPrint函数,直接调用的话还是可以捕获recover的。

总结一下就是defer recover这种机制只是针对当前函数和以及直接调用的函数可能产生的panic,它无法处理其调用产生的其它协程的panic,这一点和try catch机制不一样。

理论上讲,所有使用协程的地方都必须做defer recover处理,这样才能保证你的应用万无一失,不过开发中可以根据实际情况而定,对于一些不可能出错的函数加了还影响性能。

Go的Web服务也是一样,默认的recover机制只能捕获一层,如果你在这个请求的处理中又使用了其它协程,那么必须非常慎重,毕竟只要发生一个panic,整个Web服务就会挂掉。

最后,总结一下,Go的异常处理机制虽然没有很多其它语言高效,但是基本上还是能满足需求,目前官方已经在着完善这一点,Go2可能会见到。

推荐:《go语言教程

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

769

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

661

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

764

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

659

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1325

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

549

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

730

2023.08.11

AO3中文版入口地址大全
AO3中文版入口地址大全

本专题整合了AO3中文版入口地址大全,阅读专题下面的的文章了解更多详细内容。

1

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
golang socket 编程
golang socket 编程

共2课时 | 0.1万人学习

nginx浅谈
nginx浅谈

共15课时 | 0.8万人学习

golang和swoole核心底层分析
golang和swoole核心底层分析

共3课时 | 0.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号