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

目录
  • 正文
  • 一,正常情况下
  • 二, goroutine中panic
  • 三,间接调用recover
  • 四,nil panic
  • 五,总结

正文

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

一,正常情况下

package main
import "fmt"
func main(){
    defer func(){
        if err := recover();err != nil{
            fmt.Printf("err = %v",err)
        }
    }()
    panic("a panic")
}
打印结果:
err = a panic
Process finished with exit code 0

能正常catch panic

二, goroutine中panic

之前线上环境出现过接口出现panic导致服务不可用的情况,于是同事就直接在main函数加了个recover认为万事无忧了。实际上recover并不能捕捉到协程中的panic。

package main
import "fmt"
func main(){
    defer func(){
        if err := recover();err != nil{
            fmt.Printf("err = %v",err)
        }
    }()
    go func(){
        panic("a panic")
    }()
    select{}
}
打印结果:
panic: a panic
goroutine 6 [running]:
main.main.func2()
    I:/goProject/catchPanic.go:13 +0x40
created by main.main
    I:/goProject/catchPanic.go:12 +0x5e

实际上还是会panic导致服务不可用。

正确写法

package main
import "fmt"
func main(){
    go func(){
        defer func(){
            if err := recover();err != nil{
                fmt.Printf("err = %v",err)
            }
        }()
        panic("a panic")
    }()
    select {}
}
返回值:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
main.main()
    I:/goProject/catchPanic.go:15 +0x41
err = a panic
Process finished with exit code 2

可以看到panic被正常捕捉,同时因为select语句陷入阻塞,报了一个死锁的错。

三,间接调用recover

在我想要把recover封装成成一个函数的时候,发现recover并没有生效,因为recover只有在被defer语句直接调用的时候才会生效。当recover在其他函数内部的时候无法正确捕捉到panic。

package main
import "fmt"
func main(){
    defer cover()
    panic("a panic")
}
func cover(){
    defer func(){
        if err := recover();err!= nil{
            fmt.Println(err)
        }
    }()
}
返回值:
panic: a panic
goroutine 1 [running]:
main.main()
    I:/goProject/catchPanic.go:7 +0x62

四,nil panic

panic要被捕捉,还需要满足一种条件,就是panic不是nil panic,否则在进行捕获判断的时候无法知道是panic没有发生还是panic本身就是nil。

例如以下代码

package main
import "fmt"
func main() {
    defer func(){
        if err := recover();err != nil{
            fmt.Println(err)
        }
        fmt.Println("after recover")
    }()
    panic(nil)
    select{}
}
返回值:
after recover

recover并没有正确处理异常,因为异常的值为nil。

五,总结

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

  • 携程中出现panic
  • defer不直接调用recover
  • panic的值为nil值

写代码的时候需要注意避免因为这几种情况的出现而导致服务不可用。以上就是golang新手常遇见的一些坑。

以上就是golang recover函数使用中的一些坑解析的详细内容,更多关于golang recover函数坑的资料请关注我们其它相关文章!

(0)

相关推荐

  • Golang 错误捕获Panic与Recover的使用

    目录 一.Golang 错误是什么? 二.错误校验 1.方法 2.判断错误 三.错误捕获 1.方法 2.defer 的使用 总结 一.Golang 错误是什么? 对于Go语言(Golang)的错误是通过返回值的方式,来强迫调用者对错误进行处理,要么你通过 _ 忽略,要么你处理.对于这种设计方式,我们通常需要会写大量的 if err != nil 判断.我们可以通过方法来做到校验. 这类代码非常的多,尽管工程中 error 大部分都是nil,也就是没有任何错误,但是非nil的时候,就意味着错误就出

  • GoLang中panic与recover函数以及defer语句超详细讲解

    目录 一.运行时恐慌panic 二.panic被引发到程序终止经历的过程 三.有意引发一个panic并让panic包含一个值 四.施加应对panic的保护措施从而避免程序崩溃 五.多条defer语句多条defer语句的执行顺序 一.运行时恐慌panic panic是一种在运行时抛出来的异常.比如"index of range". panic的详情: package main import "fmt" func main() { oneC := []int{1, 2,

  • 小学生也能看懂的Golang异常处理recover panic

    🌌 专注Golang,Python语言,云原生,人工智能领域得博主 💜 过去经历的意义在于引导你,而非定义你, 💜 只要我们足够努力,任何人都有无限潜力 🚀panic 抛出异常函数 🚀recover 捕获异常函数 📣1:在一个主协成内捕获异常 package main import ( "fmt" ) func main(){ defer func(){ err := recover() if err != nil{ fmt.Println("捕获到异常") } }() panic("异常出现") //抛出异常,代表错误代码 } 🚀运行结果 📣2:假设子协成内部错误,看看主协成能不能捕获到 package main import ( "fmt" ) func Calculate(){ panic("异常出现") // 同样代表错误代码 } func main(){ defer func()

  • Golang中panic与recover的区别

    目录 前言 流程 关于recover 前言 与defer类似的是,goroutine 中也有一个_panic链表头指针指向一个_panic链,发生panic的时候也是在链表头插入_panic结构体(执行gopanic) 在执行过程中发生了panic.那么panic以后的代码不会执行,转而执行panic的逻辑,再执行defer,执行到的defer要将started标记为true,同时将其defer结构体中的_panic指针指向当前的_panic,表示这个defer是由该panic触发的.再去执行d

  • Golang异常处理之defer,panic,recover的使用详解

    目录 延迟是什么 延迟函数 延迟⽅法 延迟参数 堆栈的推迟 延迟的应⽤ panic和recover(宕机和宕机恢复) panic和recover机制 示例代码 延迟是什么 defer即延迟语句,极个别的情况下,Go才使⽤defer.panic.recover这种异常处理形式. defer可以延迟函数.延迟⽅法.延迟参数. 延迟函数 可以在函数中添加多个defer语句. 当函数执⾏到最后时,这些defer语句会按照逆序执⾏,最后该函数返回.特别是当你在进⾏⼀些打开资源的操作时,遇到错误需要提前返回

  • golang 中 recover()的使用方法

    Recover 是一个Go语言的内建函数,可以让进入宕机流程中的 goroutine 恢复过来,recover 仅在延迟函数 defer 中有效,在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果,如果当前的 goroutine 陷入恐慌,调用 recover 可以捕获到 panic 的输入值,并且恢复正常的执行.通常来说,不应该对进入 panic 宕机的程序做任何处理,但有时,需要我们可以从宕机中恢复,至少我们可以在程序崩溃前,做一些操作,举个例子,当 web 服务

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

    目录 正文 一,正常情况下 二, goroutine中panic 三,间接调用recover 四,nil panic 五,总结 正文 众所周知golang 中recover函数可以捕捉panic,防止在出现异常的情况下服务整个不可用.然而某些情况下recover也无法catch panic.下面就会说一些这些情况. 一,正常情况下 package main import "fmt" func main(){     defer func(){         if err := rec

  • golang copy函数使用的坑

    目录 坑位一:切片 dst 需要先初始化长度 坑位二:源切片中元素类型为引用类型时,拷贝的是引用 之前用 copy 不多,本以为它是个很方便的函数,没想到在做练习题时竟还是被它坑了.是我对他期望太多了. func copy(dst, src []Type) int 基本认识: 它只能用于切片,不能用于 map 等任何其他类型 它返回结果为一个 int 型值,表示 copy 的长度 坑位一:切片 dst 需要先初始化长度 不是你定义好类型,就能将 src 完全 copy 到 dst 的,你需要初始

  • go语言的panic和recover函数用法实例

    Golang 有2个内置的函数 panic() 和 recover(),用以报告和捕获运行时发生的程序错误,与 error 不同,panic-recover 一般用在函数内部.一定要注意不要滥用 panic-recover,可能会导致性能问题,我一般只在未知输入和不可靠请求时使用. golang 的错误处理流程:当一个函数在执行过程中出现了异常或遇到 panic(),正常语句就会立即终止,然后执行 defer 语句,再报告异常信息,最后退出 goroutine.如果在 defer 中使用了 re

  • PHP pthreads v3使用中的一些坑和注意点分析

    本文实例讲述了PHP pthreads v3使用中的一些坑和注意点.分享给大家供大家参考,具体如下: 一.子线程无法访问父线程的全局变量,但父线程可以访问子线程的变量 <?php class Task extends Thread { public $data; public function run() { global $num; var_dump($num); $this->data = 'abc'; //这是打印null var_dump($GLOBALS); $GLOBALS['te

  • Python自定义函数定义,参数,调用代码解析

    函数能提高应用的模块性,和代码的重复利用率.Python提供了许多内建函数,比如print()等.也可以创建用户自定义函数. 函数定义 函数定义的简单规则: 函数代码块以def关键词开头,后接函数标识符名称和圆括号(),任何传入参数和自变量必须放在圆括号中间 函数内容以冒号起始,并且缩进 若有返回值,Return[expression]结束函数:不带return表达式相当于返回None 函数通常使用三个单引号'''...'''来注释说明函数:函数体内容不可为空,可用pass来表示空语句:以下几个

  • sql脚本函数编写postgresql数据库实现解析

    这篇文章主要介绍了sql脚本函数编写postgresql数据库实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 postgresql创建Long自增函数 CREATE SEQUENCE global_id_sequence; CREATE OR REPLACE FUNCTION seq_id(OUT result bigint) AS $$ DECLARE our_epoch bigint := 1314220021721; seq_id

  • python中的函数递归和迭代原理解析

    这篇文章主要介绍了python中的函数递归和迭代原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.递归 1.递归的介绍 什么是递归? 程序调用自身的编程技巧称为递归( recursion).递归做为一种算法在程序设计语言中广泛应用. 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大

  • python匿名函数lambda原理及实例解析

    这篇文章主要介绍了python匿名函数lambda原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码如下 #-*- coding:utf-8 -*- #__author__ = "www.iplaypy.com" # 普通python函数 def func(a,b,c): return a+b+c print func(1,2,3) # 返回值为6 # lambda匿名函数 f = lambda a,b,c:a+b+c

  • Java字符串替换函数replace()用法解析

    这篇文章主要介绍了Java字符串替换函数replace()用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 replace(char oldChar, char newChar)返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 而生成的 代码如下 import java.util.*; public class Main{ public static void main(String[] args)

随机推荐