Go panic & recover 使用注意点:

1. panic:

一般表示程序出现了严重故障,此时程序不能继续运行,比如服务挂了...

产生方式/场景
(1) 主动调用:通过 panic() 函数;
(2) 被动调用:panic产生后,会将堆栈信息抛出来,方便定位问题。
例如:程序在运行阶段发生了内存异常操作,例如:空指针的取值索引越界栈溢出改写只读内存... 等等(还有其他情况会导致panic,借鉴简书大佬的链接:Go 常见的引发 panic 的情况

注意点:
1. panic 其实是一个终止函数栈执行的过程,但是在函数退出前都会执行defer里面的函数,直到所有的函数都退出后,才会执行panic

2. recover:

recover是go提供的一个用来截获 panic 信息,重新获取协程控制的函数。

使用要求
1)recover必须在defer函数中使用,但是不能被 defer 直接调用,如:

defer recover() // 直接调用,这样的写法不能恢复panic

2)recover只能恢复同一个协程中的panic,所以必须与可能发生panic的协程在同一个协程中才生效
错误示例:
panic在子协程中,而recover在主协程中,recover不能跨协程捕获panic信息,最终会导致所有的协程全部挂掉,程序会整体退出

package main

import (
	"fmt"
	"runtime/debug"
	"time"
)

// 错误示例:recover不能跨协程捕获panic信息
func Test() {
	panic("Test(): 我异常了...溜了溜了")
}

func main() {
	defer func() {
		err := recover(); if err != nil {
			debug.PrintStack()
			//fmt.Println(string(debug.Stack()))
		}
	}()

	go Test() // recover不能跨协程捕获
	// Test()
	time.Sleep(5 * time.Second) // 模拟执行耗时任务(顺便等待子协程执行)
	fmt.Println("main()不能正常执行...") // panic后,主协程main()无法继续正常执行打印
}

错误示例 - 运行结果:

正确示例: 

package main

import (
	"fmt"
	"runtime/debug"
	"time"
)

// 正确示例:
func Test() {
	defer func() {
		if err := recover(); err != nil {
			debug.PrintStack()
			//fmt.Println(string(debug.Stack()))
		}
	}()
	panic("Test(): 我异常了...溜了溜了")
}

func main() {
	go Test()
	// Test()
	time.Sleep(5 * time.Second)       // 模拟执行耗时任务(顺便等待子协程执行)
	fmt.Println("main()依然是能正常执行的...") // 可以正常打印,即使Test()发生panic
}

正确示例 - 运行结果:

3. 函数panic后,打印堆栈调用信息:

程序发生panic后,可以将堆栈信息打印出来,方便定位问题:

debug.PrintStack() 或 fmt.Println(string(debug.Stack()))


注意点:

1. 正确使用recover(),要记住recover只能恢复当前协程的panic,否则还是会导致整个进程挂掉
2. recover并非万能的,它只对用户态下的panic关键字有效

实际上在Go语言中,是存在着一些无法恢复的“恐慌”事件的,如fatalthrow方法、fatalpanic方法等,这些都是直接通过调用 exit() 方法进行中断的,属于无法恢复的“恐慌”事件,比如:
对于go1.6以上版本,如果出现 并发map读写 程序会直接以 fatal error 崩溃,即使在同一个协程内有recover()也不能恢复

  • 如果map由多协程同时读和写就会出现 fatal error:concurrent map read and map write 的错误
  • 多个协程同时写会出现 fatal error: concurrent map writes 的错误

                                                                                     写博客是真的...写了好久~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值