【Golang】并发环境下的异常处理

本文旨在对于个人知识的梳理以及知识的分享,如果有不足的地方,欢迎大家在评论区指出


对于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而导致整个程序崩掉,就可以使用上面👆的方法来实现。


参考文章:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值