golang recover函数使用中的一些坑解析
目录
- 正文
- 一,正常情况下
- 二, goroutine中panic
- 三,间接调用recover
- 四,nil panic
- 五,总结
正文
众所周知golang 中recover函数可以捕捉panic,防止在出现异常的情况下服务整个不可用。然而某些情况下recover也无法catch panic。下面就会说一些这些情况。
一,正常情况下
packagemain import"fmt" funcmain(){ deferfunc(){ iferr:=recover();err!=nil{ fmt.Printf("err=%v",err) } }() panic("apanic") } 打印结果: err=apanic Processfinishedwithexitcode0
能正常catch panic
二, goroutine中panic
之前线上环境出现过接口出现panic导致服务不可用的情况,于是同事就直接在main函数加了个recover认为万事无忧了。实际上recover并不能捕捉到协程中的panic。
packagemain import"fmt" funcmain(){ dandroideferfunc(){ iferr:=recover();err!=nil{开发者_JS学习 fmt.Printf("err=%v",err) } }() gofunc(){ panic("apanic") }() select{} } 打印结果: panic:apanic goroutine6[running]: main.main.func2() I:/goProject/catchPanic.go:13+0x40 createdbymain.main I:/goProject/catchPanic.go:12+0x5e
实际上还是会panic导致服务不可用。
正确写法
packagemain import"fmt" funcmain(){ gofunc(){ deferfunc(){ iferr:=recover();err!=nil{ fmt.Printf("err=%v",err) } }() panic("apanic") }() select{} } 返回值: fatalerror:allgoroutinesareasleep-deadlock! goroutine1[select(nocases)]: main.main() I:/goProject/catchPanic.go:15+0x41 err=apanic Processfinishedwithexitcode2
可以看到panic被正常捕捉,同时因为select语句陷入阻塞,报了一个死锁的错。
三,间接调用recover
在我想要把recover封装成成一个函数的时候,发现recover并没有生效,因为recover只有在被defer语句直接调用的时候才会生效。当recover在其他函数内部的时候无法正确捕编程客栈捉到panic。
packagemain import"fmt" funcmain(){ defercover() panic("apanic") } funccover(){ deferfunc(){ iferr:=recover();err!=nil{ fmt.Println(err) } }() } 返回值编程: panic:apanic goroutine1[running]: main.main() I:/goProj编程ect/catchPanic.go:7+0x62
四,nil panic
panic要被捕捉,还需要满足一种条件,就是panic不是nil panic,否则在进行捕获判断的时候无法知道是panic没有发生还是panic本身就是nil。
例如以下代码
packagemain import"fmt" funcmain(){ deferfunc(){ iferr:=recover();err!=nil{ fmt.Println(err) } fmt.Println("afterrecover") }() panic(nil) select{} } 返回值: afterrecover
recover并没有正确处理异常,因为异常的值为nil。
五,总结
这篇文章讲述了三种recover会失效的情况。
- 携程编程客栈中出现panic
- defer不直接调用recover
- panic的值为nil值
写代码的时候需要注意避免因为这几种情况的出现而导致服务不可用。以上就是golang新手常遇见的一些坑。
以上就是golang recover函数使用中的一些坑解析的详细内容,更多关于golang recover函数坑的资料请关注我们其它相关文章!
精彩评论