野生goroutine定义
在写go代码时,常常需要使用goroutine来执行任务:
go func() {
fmt.Println("hello")
panic("goroutine error")
}()
一旦造成了panic,那么此时recover是无法被捕获以及解决的,这种情况被我们称作野生goroutine
捕获goroutine中的panic
我们可以通过定义一个函数来捕获recover,并且执行goroutine方法
func main() {
Go(func() {
fmt.Println("hello")
panic("error")
})
}
func Go(x func()) {
if err := recover(); err != nil {
fmt.Println("panic in Go: ", err)
}
go x()
}
//hello
//panic: error
通过辅助的Go函数,发现可以捕获到recover,但进程挂掉了,在第9行中没有执行我们对错误的处理,这是一个严重的问题,接下来看一下优雅的处理方式。
优雅的解决方法
对于业务产生的panic,我们不希望退出进程给线上造成影响,Go语言中的defer可以帮我们解决这个问题,先来看一下defer的描述:
A “defer” statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.
被defer的函数在return 返回数据之后执行,这时刚好用来捕获函数抛出的panic。
当goroutine中引发panic时,此goroutine的所有defer都将会被执行。
func main() {
GoHelp(func() {
fmt.Println("hello")
panic("error")
})
time.Sleep(10 * time.Second)
}
func GoHelp(f func()) {
go func() {
defer func() {
if err := recover(); err != nil {
fmt.Println("panic in GoHelp: ", err)
}
}()
f()
}()
}
//hello
//panic in GoHelp: goroutine error
运用此方法后,发现error被捕获,而进程并没有退出。
此时由野生goroutine引发的panic,就优雅的解决了。