翼度科技»论坛 编程开发 PHP 查看内容

golang recover函数使用中的一些坑解析

10

主题

10

帖子

30

积分

新手上路

Rank: 1

积分
30
正文

众所周知golang 中recover函数可以捕捉panic,防止在出现异常的情况下服务整个不可用。然而某些情况下recover也无法catch panic。下面就会说一些这些情况。

一,正常情况下
  1. package main
  2. import "fmt"
  3. func main(){
  4.     defer func(){
  5.         if err := recover();err != nil{
  6.             fmt.Printf("err = %v",err)
  7.         }
  8.     }()
  9.     panic("a panic")
  10. }
  11. 打印结果:
  12. err = a panic
  13. Process finished with exit code 0
复制代码
能正常catch panic

二, goroutine中panic

之前线上环境出现过接口出现panic导致服务不可用的情况,于是同事就直接在main函数加了个recover认为万事无忧了。实际上recover并不能捕捉到协程中的panic。
  1. package main
  2. import "fmt"
  3. func main(){
  4.     defer func(){
  5.         if err := recover();err != nil{
  6.             fmt.Printf("err = %v",err)
  7.         }
  8.     }()
  9.     go func(){
  10.         panic("a panic")
  11.     }()
  12.     select{}
  13. }
  14. 打印结果:
  15. panic: a panic
  16. goroutine 6 [running]:
  17. main.main.func2()
  18.     I:/goProject/catchPanic.go:13 +0x40
  19. created by main.main
  20.     I:/goProject/catchPanic.go:12 +0x5e
复制代码
实际上还是会panic导致服务不可用。
正确写法
  1. package main
  2. import "fmt"
  3. func main(){
  4.     go func(){
  5.         defer func(){
  6.             if err := recover();err != nil{
  7.                 fmt.Printf("err = %v",err)
  8.             }
  9.         }()
  10.         panic("a panic")
  11.     }()
  12.     select {}
  13. }
  14. 返回值:
  15. fatal error: all goroutines are asleep - deadlock!
  16. goroutine 1 [select (no cases)]:
  17. main.main()
  18.     I:/goProject/catchPanic.go:15 +0x41
  19. err = a panic
  20. Process finished with exit code 2
复制代码
可以看到panic被正常捕捉,同时因为select语句陷入阻塞,报了一个死锁的错。

三,间接调用recover

在我想要把recover封装成成一个函数的时候,发现recover并没有生效,因为recover只有在被defer语句直接调用的时候才会生效。当recover在其他函数内部的时候无法正确捕捉到panic。
  1. package main
  2. import "fmt"
  3. func main(){
  4.     defer cover()
  5.     panic("a panic")
  6. }
  7. func cover(){
  8.     defer func(){
  9.         if err := recover();err!= nil{
  10.             fmt.Println(err)
  11.         }
  12.     }()
  13. }
  14. 返回值:
  15. panic: a panic
  16. goroutine 1 [running]:
  17. main.main()
  18.     I:/goProject/catchPanic.go:7 +0x62
复制代码
四,nil panic

panic要被捕捉,还需要满足一种条件,就是panic不是nil panic,否则在进行捕获判断的时候无法知道是panic没有发生还是panic本身就是nil。
例如以下代码
  1. package main
  2. import "fmt"
  3. func main() {
  4.     defer func(){
  5.         if err := recover();err != nil{
  6.             fmt.Println(err)
  7.         }
  8.         fmt.Println("after recover")
  9.     }()
  10.     panic(nil)
  11.     select{}
  12. }
  13. 返回值:
  14. after recover
复制代码
recover并没有正确处理异常,因为异常的值为nil。

五,总结

这篇文章讲述了三种recover会失效的情况。

  • 携程中出现panic
  • defer不直接调用recover
  • panic的值为nil值
写代码的时候需要注意避免因为这几种情况的出现而导致服务不可用。以上就是golang新手常遇见的一些坑。
以上就是golang recover函数使用中的一些坑解析的详细内容,更多关于golang recover函数坑的资料请关注脚本之家其它相关文章!

来源:https://www.jb51.net/article/275915.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具