Golang学习日志 ━━ 宕机恢复神器recover的一些要点

golang通过deferpanicrecover来实现其它语言中类似try...catch...的功能。

几个要点注意

总结一下就是defer recover这种机制只是针对当前函数和以及直接调用的函数可能产生的panic,它无法处理其调用产生的其它协程的panic,这一点和try catch机制不一样。
理论上讲,所有使用协程的地方都必须做defer recover处理,这样才能保证你的应用万无一失,不过开发中可以根据实际情况而定,对于一些不可能出错的函数加了还影响性能。
Go的Web服务也是一样,默认的recover机制只能捕获一层,如果你在这个请求的处理中又使用了其它协程,那么必须非常慎重,毕竟只要发生一个panic,整个Web服务就会挂掉。

  • panic的返回值,通过recover函数来获取。 recover函数也是一个内置函数,专门用来接收panic函数返回值。当panic函数没有被调用或者没有返回值时,recover返回Nil.
    参考:《panic和recover的使用规则
  • 执行完对应的 defer 后,从宕机点退出当前函数后继续执行。
    参考:《Go语言宕机恢复(recover)——防止程序崩溃
  • 虽然 panic/recover 能模拟其他语言的异常机制,但并不建议在编写普通函数时也经常性使用这种特性。

流程分析

在这里插入图片描述

案例一:
package main
import "fmt"
func main() {  
	f()  
	fmt.Println("Returned normally from f.")  
}

func f() {  
	defer func() {  
		if r := recover(); r != nil {  
			fmt.Println("Recovered in f", r)  
		}
	}()
	fmt.Println("Calling g.")  
	g(0)  
	fmt.Println("Returned normally from g.")  
}

func g(i int) {  
	if i > 3 {  
		fmt.Println("Panicking!")  
		panic(fmt.Sprintf("%v", i))  
	}
	defer fmt.Println("Defer in g", i)  
	fmt.Println("Printing in g", i)  
	g(i + 1)  
}

代码输出结果:

Calling g.  
Printing in g 0  
Printing in g 1  
Printing in g 2  
Printing in g 3  
Panicking!  
Defer in g 3  
Defer in g 2  
Defer in g 1  
Defer in g 0  
Recovered in f 4  
Returned normally from f.  
案例二:
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
运行后
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值