【Golang】panic和recover作用|Go主题月

2,454 阅读2分钟

关键字介绍

  • panic:一旦出现,就意味着程序的结束并退出。Go 语言中 panic 关键字主要用于主动抛出异常,类似 java 等语言中的 throw 关键字。
  • recover:将程序状态从严重的错误中恢复到正常状态。Go 语言中 recover 关键字主要用于捕获异常,让程序回到正常状态,类似 java 等语言中的 try ... catch

使用

  • panic

    1. 发生panic后,后续代码不会执行
    2. 发生panic后,会执行defer链表

    我们先创建两个协程,然后在其中一个协程里发生panic。看看另一个协程会怎么样。

    package main
    
    import "fmt"
    
    func main() {
        // 第一个协程
    	go func() {
           
    		var i int
    		for {
    			i++
    			fmt.Println("协程1")
    			time.Sleep(1*time.Second)
                 // 3秒后发生panic
    			if i==3 {
    				panic("异常退出")
    			}
    		}
    
    	}()
    	// 第二个协程
    	go func() {
    		for  {
    			fmt.Println("协程2")
    			time.Sleep(1*time.Second)
    		}
    	}()
        // 让主协程不退出
    	for  {
    		time.Sleep(1*time.Second)
    	}
    }
    

    当程序执行5秒后,其中一个协程就会发生panic("异常退出"),这时程序就会退出,随之另一个协程也结束了。

    输出:

    协程2
    协程1
    协程2
    协程1
    协程2
    协程1
    协程2
    panic: 异常退出
    
    goroutine 6 [running]:
    main.main.func1()
            /home/zheng/STUDY/GoWork/demo/main.go:28 +0xb9
    created by main.main
            /home/zheng/STUDY/GoWork/demo/main.go:15 +0x35
    
    

    所以panic如果不捕获,就会导致程序整体关闭的严重的后果

  • recovery

    1. 为了解决panic的问题,go也提供了recovery这个函数,用于捕获异常,保证程序能正常运行。

    2. 只对当前goroutine发生的panic有效

    3. recovery要配合defer使用,因为recovery要在发生panic后执行才有效,但是发生panic的后续代码不会执行了,但是会执行defer

    我们对上面程序的第一个协程加上recovery

     // 第一个协程
    go func() {
        // 捕获异常
        defer func() {
            err:=recover()
            fmt.Printf("捕获的:%s\n",err)
        }()
        
        var i int
        for {
            i++
            fmt.Println("协程1")
            time.Sleep(1*time.Second)
            // 3秒后发生panic
            if i==3 {
                panic("异常退出")
            }
        }
    
    }()
    

    输出:

    协程2
    协程1
    协程1
    协程2
    协程2
    协程1
    协程2
    捕获的:异常退出
    协程2
    协程2
    ...
    

    可以看到线程1的recovery捕获当前协程的panic的异常,并输出异常原因。但是另一个协程2还会继续执行。