为何Go中recover无法捕获所在函数内goroutine触发的panic?
为什么你的recover没捕获到goroutine里的panic?
核心原因很简单:Go语言中,recover()只能捕获当前goroutine内触发的panic,不同goroutine之间的panic是完全隔离的,跨goroutine无法实现panic捕获。
具体到你的代码,拆解执行流程就能明白:
wrapRecover函数里的defer是注册在执行TestRecover的测试goroutine中的。- 你传给
wrapRecover的匿名函数,仅仅是调用group.Go启动了一个新的goroutine,这个匿名函数本身很快就执行完毕,随后wrapRecover函数返回,它的defer也会跟着执行(这时候新goroutine还在sleep,根本没触发panic)。 - 1秒后,新goroutine里的
fn()触发panic,但这个panic属于那个独立的goroutine,和之前的测试goroutine没有关联,自然不会被已经执行完的wrapRecover里的recover捕获。
正确的修复方式
要捕获新goroutine里的panic,必须把recover()逻辑放在同一个goroutine的defer中。比如修改group.Go中的匿名函数:
group.Go(func() error { defer func() { if rec := recover(); rec != nil { fmt.Println("recover") } }() fn() return nil })
或者封装一个通用的带panic捕获的函数,复用起来更方便:
func wrapGoroutineWithRecover(f func()) func() error { return func() error { defer func() { if rec := recover(); rec != nil { fmt.Println("recover") } }() f() return nil } } // 调用时直接传入即可 group.Go(wrapGoroutineWithRecover(fn))
内容的提问来源于stack exchange,提问作者vovanchello
相关产品推荐
相关产品推荐

