美文网首页
Go语言宕机恢复recover---防止程序崩溃

Go语言宕机恢复recover---防止程序崩溃

作者: 码二哥 | 来源:发表于2020-02-08 10:38 被阅读0次

    参考:
    http://c.biancheng.net/view/64.html

    关键点

    希望通过下面的关键词,能够实现目的:能够快速回忆理解复习 知识点:

    1、如何使用defer?

    恢复recover必须结合defer才有效,单独使用,没有效果,

    2、panic类似于Java中的throw抛出异常

    3、recover类似于Java中的try catch捕获异常的

    4、恢复recover的作用

    使得宕机中的goroutine恢复过来, 让程序崩盘时,继续执行

    5、其他语言中,如Java,宕机,常常是以异常形式存在,如果有严重异常没有捕获到的话,就会宕机

    Recover 是一个Go语言的内建函数,可以让进入宕机流程中的 goroutine 恢复过来,recover 仅在延迟函数 defer中有效,在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果,如果当前的 goroutine 陷入恐慌,调用 recover 可以捕获到 panic 的输入值,并且恢复正常的执行。

    通常来说,不应该对进入 panic 宕机的程序做任何处理,但有时,需要我们可以从宕机中恢复,至少我们可以在程序崩溃前,做一些操作,举个例子,当 web 服务器遇到不可预料的严重问题时,在崩溃前应该将所有的连接关闭,如果不做任何处理,会使得客户端一直处于等待状态,如果 web 服务器还在开发阶段,服务器甚至可以将异常信息反馈到客户端,帮助调试。

    提示:
    在其他语言里,宕机往往以异常的形式存在,底层抛出异常,上层逻辑通过 try/catch 机制捕获异常,

    没有被捕获的严重异常会导致宕机捕获的异常可以被忽略,让代码继续运行。

    Go语言没有异常系统,其使用 panic 触发宕机类似于其他语言的抛出异常,recover 的宕机恢复机制就对应其他语言中的 try/catch 机制。

    1、让程序在崩溃时继续执行

    下面的代码实现了 ProtectRun() 函数,该函数传入一个匿名函数或闭包后的执行函数,当传入函数以任何形式发生 panic 崩溃后,可以将崩溃发生的错误打印出来,同时允许后面的代码继续运行,不会造成整个进程的崩溃。

    保护运行函数:

    package main
    import (
        "fmt"
        "runtime"
    )
    // 崩溃时需要传递的上下文信息
    type panicContext struct {
        function string // 所在函数
    }
    // 保护方式允许一个函数
    func ProtectRun(entry func()) {
        // 延迟处理的函数
        defer func() {
            // 发生宕机时,获取panic传递的上下文并打印
            err := recover()
            switch err.(type) {
            case runtime.Error: // 运行时错误
                fmt.Println("runtime error:", err)
            default: // 非运行时错误
                fmt.Println("error:", err)
            }
        }()
        entry()
    }
    func main() {
        fmt.Println("运行前")
        // 允许一段手动触发的错误
        ProtectRun(func() {
            fmt.Println("手动宕机前")
            // 使用panic传递上下文
            panic(&panicContext{
                "手动触发panic",
            })
            fmt.Println("手动宕机后")
        })
        // 故意造成空指针访问错误
        ProtectRun(func() {
            fmt.Println("赋值宕机前")
            var a *int
            *a = 1
            fmt.Println("赋值宕机后")
        })
        fmt.Println("运行后")
    }
    

    代码输出结果:

    运行前
    手动宕机前
    error: &{手动触发panic}
    赋值宕机前
    runtime error: runtime error: invalid memory address or nil pointer dereference
    运行后
    

    对代码的说明:

    • 第 9 行声明描述错误的结构体,保存执行错误的函数。

    • 第 17 行使用 defer 将闭包延迟执行,当 panic 触发崩溃时,ProtectRun() 函数将结束运行,此时 defer 后的闭包将会发生调用。

    • 第 20 行,recover() 获取到 panic 传入的参数。

    • 第 22 行,使用 switch 对 err 变量进行类型断言。

    • 第 23 行,如果错误是有 Runtime 层抛出的运行时错误,如空指针访问、除数为 0 等情况,打印运行时错误。

    • 第 25 行,其他错误,打印传递过来的错误数据。

    • 第 44 行,使用 panic 手动触发一个错误,并将一个结构体附带信息传递过去,此时,recover 就会获取到这个结构体信息,并打印出来。

    • 第 57 行,模拟代码中空指针赋值造成的错误,此时会由 Runtime 层抛出错误,被 ProtectRun() 函数的 recover() 函数捕获到。

    2、panic 和 recover 的关系

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

    • 有 panic 没 recover,程序宕机。

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

    3、提示

    虽然 panic/recover 能模拟其他语言的异常机制,但并不建议在编写普通函数时经常性使用这种特性。

    在 panic 触发的 defer 函数内,可以继续调用 panic,进一步将错误外抛,直到程序整体崩溃

    如果想在捕获错误时设置当前函数的返回值,可以对返回值使用命名返回值方式直接进行设置。

    相关文章

      网友评论

          本文标题:Go语言宕机恢复recover---防止程序崩溃

          本文链接:https://www.haomeiwen.com/subject/skabxhtx.html