问题描述
我一直试图找到可以回答这个问题的东西,但我找不到任何可以谈论它的东西。
func main() {
// assume this wrapped in a waitgroup or something
// so that it doesnt exit
go queue.ConsumeAndDoSomething()
go api.StartServer()
}
我在这里有两个 goroutines 做完全不同的事情,如果另一个 goroutine 崩溃/恐慌,理想情况下应该继续运行。如果队列操作失败,API 服务器应该会受到影响,反之亦然。
我不确定这是否可能(甚至推荐)。有没有一种干净的方法可以做到这一点,还是应该在 goroutine 恐慌时整个程序退出?
解决方法
您必须使用内置的 recover()
函数从恐慌中恢复,并且必须在 deferred 函数中调用它。
假设您有一个可能会恐慌的函数:
func doPanic() {
log.Println("about to panic")
panic("test")
}
创建一个辅助函数来启动一个作为“受保护”的 goroutine 的函数(免受恐慌):
func protect(f func()) {
defer func() {
if err := recover(); err != nil {
log.Printf("Recovered: %v",err)
}
}()
f()
}
像这样使用它:
func main() {
go protect(doPanic)
for {
time.Sleep(time.Second)
fmt.Println("tick")
}
}
此测试应用将输出:
2021/03/04 14:12:31 about to panic
2021/03/04 14:12:31 Recovered: test
tick
tick
tick
...
查看相关问题:Generic panic recovering in go programs
,如果您希望其他 goroutine 不受影响,则每个 goroutine 都必须推迟 recover
调用以从潜在的恐慌中恢复。
代替
go queue.ConsumeAndDoSomething()
你应该使用
go func(){
defer func() {
if r := recover(); r != nil {
log.Error("goroutine paniqued: ",r)
}
}()
queue.ConsumeAndDoSomething()
}()