panic
panic通常是不可以恢复的错误程序
panic 抛出异常的时候,会把程序的堆栈信息打印出来。
程序执行到panic的时候,是不会继续向下执行的。
使用panic的调用程序,是不会阻止defer程序的执行的:
func TestPanic(t *testing.T) {
defer func() {
fmt.Println("finally")
}()
fmt.Println("start")
panic(errors.New("Something wrong"))
}
复制代码
程序输出
=== RUN TestPanic
start
finally
--- FAIL: TestPanic (0.00s)
panic: Something wrong [recovered]
panic: Something wrong
goroutine 6 [running]:
testing.tRunner.func1.2({0x975600, 0xc000042530})
D:/Go/src/testing/testing.go:1209 +0x24e
testing.tRunner.func1()
D:/Go/src/testing/testing.go:1212 +0x218
panic({0x975600, 0xc000042530})
D:/Go/src/runtime/panic.go:1038 +0x215
command-line-arguments.TestPanic(0x0)
复制代码
os.Exit() 推出程序,是不会运行defer的具体函数的
func TestPanic(t *testing.T) {
defer func() {
fmt.Println("finally")
}()
fmt.Println("start")
os.Exit(1)
//panic(errors.New("Something wrong"))
}
复制代码
输出
=== RUN TestPanic
start
复制代码
recover
recover主要是防止代码执行panic的时候,导致进程崩溃,使用recover,可以让进程依旧继续运行
func TestRecover(t *testing.T) {
defer func() {
if err := recover(); err != nil {
fmt.Println("Catch Error", err)
}
}()
fmt.Println("start")
panic(errors.New("this error"))
}
复制代码
输出结果
=== RUN TestRecover
start
Catch Error this error
--- PASS: TestRecover (0.00s)
PASS
复制代码
这里虽然执行了panic的函数,但是执行panic之后,在defer里面,又继续调用了recover进行异常的捕捉,这种实现方式,有点像php或java里面的try {} catch() {}的逻辑
但是recover方式也不建议盲目使用:
假如服务器的没有对应的应用资源,导致执行panic,进行异常抛出,但是又再次使用recover进行恢复,一些health check的程序,只是check了一下进程是否存在。就会导致所谓的僵尸进程:进程还在,但是没有资源执行对应的逻辑。
所以使用recover的时候,还是需要经过一些思考的,不能盲目的使用。