Golang崩溃预防

huangapple go评论74阅读模式
英文:

Golang panic crash prevention

问题

在Golang中,如果没有recover,panic会导致进程崩溃,所以我不得不在每个函数的开头放置以下代码片段:

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

只是为了防止我的程序崩溃。现在我在想,这真的是正确的做法吗?因为我觉得在每个地方都放置相同的代码看起来有点奇怪。

在我看来,Java的方式,将异常向上冒泡到调用函数,直到主函数,是一种更好的控制异常/panic的方式。我理解这是Go的设计,但是Go立即崩溃进程的优势是什么?

英文:

In Golang a panic without a recover will crash the process, so I end up putting the following code snippet at the beginning of every function:

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

just in order to prevent my program from crashing. Now I'm wondering, is it really the way to go? Because I think it looks a little bit strange to put the same code everywhere.

It seems to me, the Java way, bubbling the exceptions up to the calling function, until the main function is a better way to control the exceptions/panics. I understand it's by Go's design, but what is the advantage of immediately crashing the process just like what Go does?

答案1

得分: 13

只有在确切知道原因的情况下,才应该从 panic 中恢复。Go 程序在以下两种情况下会发生 panic:

  • 程序逻辑错误(例如空指针解引用、越界访问数组或切片)
  • 故意引发 panic(使用 panic(...),可以是你的代码或你的代码调用的代码)

在第一种情况下,崩溃是合适的,因为这意味着你的程序已经进入了一个糟糕的状态,不应该继续执行。在第二种情况下,只有在预期到 panic 时才应该从中恢复。最好的解释是,这种情况非常罕见,如果你遇到了,你会知道。我几乎可以肯定,无论你正在编写什么代码,你都不需要从 panic 中恢复。

英文:

You should only recover from a panic if you know exactly why. A Go program will panic under essentially two circumstances:

  • A program logic error (such as a nil pointer dereference or out-of-bounds array or slice access)
  • An intentional panic (called using panic(...)) from either your code or code that your code calls

In the first case, a crash is appropriate because it means that your program has entered a bad state and shouldn't keep executing. In the second case, you should only recover from the panic if you expect it. The best way to explain this is simply to say that it's extremely rare, and you'll know that case if you see it. I'm almost positive that whatever code you're writing, you don't need to recover from panics.

答案2

得分: 3

通常情况下,即使有异常情况,你也会在一个"FaultBarrier"中捕获它们。通常情况下,这是所有新线程生成的地方。目的是捕获和记录意外的失败。

在Go语言中,你使用返回值来处理所有预期的失败情况。你所使用的框架通常会有一个故障屏障来捕获一个会话(例如通常是一个HTTP事务)并记录问题。我只在非幂等的Close函数等地方看到recover的使用。如果你遇到一种情况,无法确定某个东西是否已经关闭,但又知道它必须关闭,那么你可以使用recover,这样第二次关闭时的panic将被忽略,而不会一直失败到FaultBarrier。

英文:

Generally, even with exceptions, you catch them at a "FaultBarrier". It's usually the place where all new threads are spawned. The point is to catch and log unexpected failures.

In Go, you use return values for all expected failures. The framework in which you work will generally have a fault barrier to catch a session (ie: usually an http transaction) and log the problem. The only other place I see recover happening is things like non-idempotent Close function. If you have a situation where you can't tell if something is already closed but know it must be closed, then you could end up doing a recover so that a second close panic will be ignored, rather than failing what you are doing all the way up to the FaultBarrier.

答案3

得分: 0

我认为panic和异常不同。你可以处理异常并继续运行程序,而panic会导致当前例程终止,你无法跳过它。

异常通常由操作系统发出,并导致相关例程运行。而panic是由程序员手动触发的,会导致goroutine退出。

你可以为函数中的每一段代码定义多个异常,而panic恢复机制适用于整个函数。

异常设计用于处理,而panic设计用于终止,panic恢复机制似乎只是一种控制终止的技巧。

因此,异常处理类似于错误处理。

但是在Go语言中,你如何利用它的优势呢?

我将描述我的使用案例来回答你的问题。

有两种类型的阻塞错误,panicfatal。你无法从致命错误中恢复。

有时你需要终止进程,但有时你需要重新启动它。

我使用recover()机制来从panic错误中恢复,以关闭当前的goroutine并重新启动主要功能。

因此,我必须小心处理错误类型。有些情况下需要发出致命错误,比如缺少必要的配置文件。有时重新启动应用程序是合理的。考虑在崩溃后希望重新启动应用程序的所有情况,例如:

  • 超载的服务(导致拒绝服务)
  • 缺少数据库管理系统
  • 其他使用的Go包中出现的意外错误
  • 例如崩溃的imagick进程
  • 等等

**因此,**在我的情况下,recover()非常有益。它为退出之前清楚地关闭进程提供了机会。

*附注:**你可以开发一个引导程序应用程序,它将作为独立的进程运行主要应用程序。如果该进程异常退出,它必须重新运行主要应用程序。

在保持应用程序运行的同时,使用日志记录进行调试。

英文:

I think panic is not same as exception. You can handle exception and running of routine will be continued. Whereas panic causes to termination current routine and you can not skip it.
Exception emits by OS generally and causes to run related routine. Instead panic emits by programmer manually and causes to exit goroutine.
You can define multiple exception for every piece of code within a function. Panic recovery mechanism works for whole function.
Exception designed to be handled whereas Panic designed to termination and panic recovering mechanism seems to be just a trick to control termination.

So exception handling is comparable with error handling.
But how you can take advantages of it in Golang?

I will describe my use case to answer your question.

There is two type of blocking error, Panic and Fatal. You can not recover from fatal error.
Sometimes you need to kill the process. But sometimes you need to restart it.
I used recover() mechanism to recovering from panic error in order to shutting down current goroutine and restarting main functionality.
So I must be careful about error type. Some situations need to emit fatal error such as missing necessary config file. And sometimes it is reasonable to restart the app. Think about all situations that you like to restart the app after crash. Such as:

  • overloaded service (which causes to DoS)
  • missing DBMS
  • unexpected error origin from other used go packages
  • crashing imagick process for example
  • and so on

So,
recover() is very beneficial in my case. It gives a chance to shutdown the process clearly before exiting.

Side Note: You can develop an bootstrapper app which will runs main app as detached process. It must re-run main app, if that process exited abnormally.
Use logging in order to debug while keeping your app run.

huangapple
  • 本文由 发表于 2014年8月18日 13:01:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/25356602.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定