本文旨在对于个人知识的梳理以及知识的分享,如果有不足的地方,欢迎大家在评论区指出
对于go中的多个协程同时运行的情况,如果其中一个协程发生了panic
,那么就会导致其它的协程也无法正常运行,此时就需要对发生异常的协程做异常处理,以保证其它的协程可以正常的运行
-
对于错误堆栈信息的打印
import main // 打印错误的堆栈信息 func PrintStack() { var buf [4096]byte n := runtime.Stack(buf[:], false) fmt.Printf("==> %s\n", string(buf[:n])) } func test() { zero := 0 // 这里会发生除0panic a := 10 / zero fmt.Println(a) } func main() { // 这里需要加入go的同步机制,防止主线程将test函数的线程杀死 wg := new(sync.WaitGroup) wg.Add(1) go func() { defer func() { if e:=recover(); e!=nil { PrintStack() wg.Done() } }() test() }() wg.Wait() } // 返回结果 ==> goroutine 18 [running]: main.PrintStack() /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:12 +0x5b main.main.func1.1(0xc0000b4004) /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:58 +0x45 panic(0x10b8780, 0x1169e90) /usr/local/Cellar/go@1.15/1.15.11/libexec/src/runtime/panic.go:969 +0x1b9 main.test() /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:36 +0x11 main.main.func1(0xc0000b4004) /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:63 +0x4a created by main.main /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:55 +0x6b
从上面报错的堆栈信息可以看出来,在main.test()这行中展示了第36行发生了异常,这样就非常方便的获取到了异常发生的位置
-
并发情况下的
panic
处理package main import ( "fmt" "runtime" "sync" ) // 打印错误的堆栈信息 func PrintStack() { var buf [4096]byte n := runtime.Stack(buf[:], false) fmt.Printf("==> %s\n", string(buf[:n])) } func GoroutineNotPanic(handlers ...func() error) { var wg sync.WaitGroup for _, f := range handlers { wg.Add(1) go func(handler func() error) { defer func() { if e := recover(); e != nil { // 某个服务的调用出现了错误,可以在这里打印错误的堆栈信息 PrintStack() } wg.Done() }() handler() }(f) } wg.Wait() } func main() { aRpc := func() error { panic("rpc logic A panic") return nil } bRpc := func() error { fmt.Println("rpc logic B") return nil } // 声明两个函数aRpc与bRpc,其中aRpc中手动触发panic GoroutineNotPanic(aRpc, bRpc) } // 返回结果 rpc logic B ==> goroutine 6 [running]: main.PrintStack() /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:12 +0x5b main.GoroutineNotPanic.func1.1(0xc0000160a0) /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:25 +0x59 panic(0x10b4820, 0x10edc40) /usr/local/Cellar/go@1.15/1.15.11/libexec/src/runtime/panic.go:969 +0x1b9 main.main.func1(0x0, 0x0) /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:37 +0x39 main.GoroutineNotPanic.func1(0xc0000160a0, 0x10d6190) /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:29 +0x4f created by main.GoroutineNotPanic /Users/bytedance/go/src/Demo/go并发环境下的异常处理.go:21 +0x91
了解了上面的并发环境下的异常处理机制之后,对于调用多个服务,并且不考虑它们先后顺序的场景,如果不想因为某些服务发生panic而导致整个程序崩掉,就可以使用上面👆的方法来实现。
参考文章: