Contents
4.8. 宕机恢复-recover¶
由于 panic、recover 参数类型为 interface{},因此可抛出任何类型对象。
func panic(v interface{})
func recover() interface{}
向已关闭的通道发送数据会引发panic
package main
import "fmt"
func main() {
defer func() {
if err :=recover();err !=nil {
fmt.Println(err) //send on closed channel
}
}()
// 创建通道
var ch chan int = make(chan int,10 )
// 关闭通道
close(ch)
ch <- 1 // 向通道里面传入一个值
}
延迟调用中引发的错误,可被后续延迟调用捕获,但仅最后一个错误可被捕获。
package main
import "fmt"
func main() {
defer func() {
fmt.Println(recover()) //defer panic
}()
defer func() {
panic("defer panic")
}()
panic("panic.....")
}
Go实现类似 try catch 的异常处理
package main
import "fmt"
func Try(fun func(), handler func(interface{})) {
defer func() {
if err := recover(); err != nil {
handler(err)
}
}()
fun()
}
func main() {
Try(func() {
panic("test panic") //test panic
}, func(err interface{}) {
fmt.Println(err)
})
}
无论是代码运行错误由Runtime层抛出的panic崩溃,还是主动触发的panic崩溃, 都可以配合defer和recover实现错误捕捉和恢复,让代码在发送崩溃后允许继续运行。
在其他语言中,可以通过try/catch机制捕获异常,没有捕获的严重异常会导致宕机,
捕获的异常可以忽略,让代码继续运行。
Go没有异常系统,使用panic触发宕机类似于其他语言的排除异常,
那么recover的宕机恢复机制就对应try/catch机制。
4.8.1. 1.让程序在崩溃时继续执行¶
package main
import (
"fmt"
"runtime"
)
// 崩溃时需要传递的上下文信息,声明错误的结构体,成员保存错误的执行函数
type panicContext struct {
function string // 所在函数
}
// 保护方式允许一个函数
func ProtectRun(entry func()) {
// 延迟处理的函数,defer将闭包延迟执行,当panic触发崩溃时,ProtectRun()函数将结束运行,此时defer后的闭包将会调用
defer func() {
// 发生宕机时,获取panic传递的上下文并打印
err := recover() // recover()获取painc传入的参数
switch err.(type) { // 使用switch对err变量进行类型断言
case runtime.Error: // 运行时错误
fmt.Println("runtime error:", err)
default: // 非运行时错误
fmt.Println("error:", err)
}
}()
entry()
}
func main() {
fmt.Println("运行前")
// 允许一段手动触发的错误
ProtectRun(func() {
fmt.Println("手动宕机前")
// 使用panic传递上下文,将一个结构体附带信息传递过去,此时,recover获取结构体信息,并打印出来
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
//运行后
4.8.2. 2. panic和recover的关系¶
panic与defer组合有如下几个特性:
有panic没有cover程序宕机。
有panic也有conver捕获,程序不会宕机。执行完对应的defer后,从宕机点退出当前函数后继续执行。
在painc触发的defer函数内,可以继续调用panic,进一步将错误外抛直到程序整体崩溃。