• Go从入门到精通——函数——宕机恢复(recover)——防止程序崩溃


    宕机恢复(recover)——防止程序崩溃

      无论是代码运行错误由 Runtime 层抛出的 panic 崩溃,还是主动触发的 panic 崩溃,都可以配合 defer 和 recover 实现错误捕捉和恢复,让代码在发生崩溃后允许继续运行。

    提示: 在其他语言里,宕机往往以一场的形式存在,底层抛出一场,上层逻辑通过 try/catch 机制捕获异常,没有被捕获的严重异常会导致宕机,捕获的异常可以被忽略,让代码继续运行。
    Go 没有异常系统,其使用 panic 触发宕机类似于其他语言的抛出异常,那么 recover 的宕机恢复机制就对应 try/catch 机制。

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

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

    package main
    
    import (
    	"fmt"
    	"runtime"
    )
    
    //声明描述错误的结构体,成员保存错误的执行函数。
    //崩溃时需要传递的上下文信息
    type panicContext struct {
    	function string
    }
    
    //保护方式允许一个函数
    func ProtectRun(entry func()) {
    
    	//延迟处理的函数。使用defer将闭包延迟执行,
    	//当 panic 触发崩溃时,ProtectRun()函数将结束运行,此时 defer 后的闭包将会发生调用。
    	defer func() {
    
    		//发生宕机时,recover() 获取 panic 传递的上下文并打印
    		err := recover()
    
    		switch err.(type) {
    		//如果错误是runtime层抛出的运行时从无哦,如空指针访问、除数为0等情况,打印运行时错误。
    		case runtime.Error:
    			fmt.Println("runtime error:", err)
    		default:
    			fmt.Println("error:", err)
    		}
    	}()
    	entry()
    }
    
    func main() {
    	fmt.Println("运行前")
    
    	//允许一段手动触发的错误
    	ProtectRun(func() {
    		fmt.Println("手动宕机前")
    
    		//使用 panic 传递上下问。使用 panic 手动触发一个错误,并将一个结构体附带信息传递过去,
    		//此时,recover 就会获取到这个结构体信息,并打印出来。
    		panic(&panicContext{"手动触发panic"})
    
    		fmt.Println("手动宕机后")
    	})
    
    	//故意造成空指针访问错误
    	ProtectRun(func() {
    
    		fmt.Println("赋值宕机前")
    
    		var a *int
    
    		//模拟代码中空指针赋值造成的错误,此时会由 Runtime 层抛出错误,被 ProtectRun() 函数的 recover() 函数捕获到。
    		*a = 1
    
    		fmt.Println("赋值宕机后")
    	})
    
    	fmt.Println("运行后")
    }

      代码输出如下:

    Starting: D:\go-testfiles\bin\dlv.exe dap --check-go-version=false --listen=127.0.0.1:54313 from d:\go-testfiles
    DAP server listening at: 127.0.0.1:54313
    Type 'dlv help' for list of commands.
    运行前
    手动宕机前
    error: &{手动触发panic}
    赋值宕机前
    runtime error: runtime error: invalid memory address or nil pointer dereference
    运行后
    Process 15388 has exited with status 0

    二、panic 和 recover 的关系

      panic 和 defer 的组合有如下几个特性。

    • 有 panic 没 recover,程序宕机。
    • 有 panic 也有 recover 捕获,程序不会宕机。执行完对应的 defer 后,从宕机点退出当前函数后继续执行。
  • 相关阅读:
    ubuntu: 环境搭建
    [转]unable to resolve superclass of 的奇怪问题和一种解决方法!
    [转]如何利用ndk-stack工具查看so库的调用堆栈【代码示例】?
    [转]TCP、UDP数据包大小的确定
    [转]教大家如何打造使用Tcpview(tcp查看器
    [转]帐号登录事件(事件编号与描述)
    [转]一个基于完成端口的TCP Server Framework,浅析IOCP
    [转]宏的高级使用--##,__VA_ARGS__, __FILE__, __FUNCTION__等
    mysql5.5 Replication 主从同步
    [转]adb pull Permission denied及no such file错误
  • 原文地址:https://www.cnblogs.com/zuoyang/p/16322410.html
Copyright © 2020-2023  润新知