15

在 Golang 中,没有恢复的恐慌会使进程崩溃,所以我最终将以下代码片段放在每个函数的开头:

defer func() {
    if err := recover(); err != nil {
        fmt.Println(err)
    }
}()

只是为了防止我的程序崩溃。现在我想知道,这真的是要走的路吗?因为我觉得到处都放同样的代码看起来有点奇怪。

在我看来,Java 方式将异常冒泡到调用函数,直到 main 函数是控制异常/恐慌的更好方法。我知道这是 Go 的设计,但是像 Go 一样立即使进程崩溃有什么好处?

4

3 回答 3

12

只有知道确切原因,您才应该从恐慌中恢复过来。Go 程序在两种情况下会出现恐慌:

  • 程序逻辑错误(例如 nil 指针取消引用或越界数组或切片访问)
  • panic(...)来自您的代码或您的代码调用的代码的故意恐慌(称为 using )

在第一种情况下,崩溃是合适的,因为这意味着您的程序已进入错误状态并且不应继续执行。在第二种情况下,您应该只在预期的情况下从恐慌中恢复过来。解释这一点的最好方法就是简单地说它非常罕见,如果你看到它就会知道这种情况。我几乎可以肯定,无论您编写什么代码,您都不需要从恐慌中恢复。

于 2014-08-18T05:05:31.763 回答
3

通常,即使有异常,您也会在“FaultBarrier”处捕获它们。它通常是产生所有新线程的地方。关键是要捕获并记录意外故障。

在 Go 中,您对所有预期的失败都使用返回值。您工作的框架通常会有一个故障屏障来捕获会话(即:通常是一个 http 事务)并记录问题。我看到恢复发生的唯一其他地方是诸如非幂等关闭函数之类的事情。如果您无法判断某事是否已经关闭但知道它必须关闭,那么您最终可能会进行恢复,以便忽略第二次关闭恐慌,而不是让您正在做的所有事情都失败直至 FaultBarrier。

于 2016-08-28T14:56:38.167 回答
0

我认为panic与异常不同。您可以处理异常并继续运行例程。而恐慌导致终止当前例程,您不能跳过它。
异常通常由操作系统发出并导致运行相关例程。相反,恐慌由程序员手动发出并导致退出goroutine
您可以为函数中的每段代码定义多个异常。恐慌恢复机制适用于整个功能。
异常被设计为被处理,而 Panic 被设计为终止和恐慌恢复机制似乎只是控制终止的一个技巧。

所以异常处理与错误处理是可比的。
但是如何在 Golang 中利用它呢?

我将描述我的用例来回答您的问题。

有两种类型的阻塞错误,Panic 和 Fatal。您无法从致命错误中恢复。
有时您需要终止该进程。但有时您需要重新启动它。
我使用recover()了从恐慌错误中恢复的机制,以关闭当前的 goroutine 并重新启动主要功能。
所以我必须小心错误类型。某些情况需要发出致命错误,例如缺少必要的配置文件。有时重启应用程序是合理的。考虑一下您希望在崩溃后重新启动应用程序的所有情况。如:

  • 服务超载(导致 DoS)
  • 缺少数据库管理系统
  • 来自其他使用过的 go 包的意外错误
  • imagick例如崩溃过程
  • 等等

所以,
recover()对我来说是非常有益的。它使您有机会在退出之前清楚地关闭该过程。

旁注:您可以开发一个引导程序应用程序,它将主应用程序作为分离进程运行。如果该进程异常退出,它必须重新运行主应用程序。
使用日志记录以便在保持应用运行的同时进行调试。

于 2021-08-23T12:55:27.343 回答