目录
正文一,正常情况下二, 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(){
deferfunc(){
iferr:=recover();err!=nil{
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:/goProject/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会失效的情况。
携程中出现panicdefer不直接调用recoverpanic的值为nil值
写代码的时候需要注意避免因为这几种情况的出现而导致服务不可用。以上就是golang新手常遇见的一些坑。
以上就是golang recover函数使用中的一些坑解析的详细内容,更多关于golang recover函数坑的资料请关注中国红客联盟其它相关文章!