我认为一个等效的问题是-是否所有运行时错误(可能致命, panic )?因为任何 panic 症都应该是可以恢复的。我不是在说从os.Exit()log.Fatal()或Go运行时中的错误或某人通过电源线跳闸中恢复,而是从其他运行时错误中恢复,这将导致程序崩溃。

这是可以通过紧急/恢复捕获的运行时错误的示例:

package main

import (
    "fmt"
)

func errorHandler() {
    r := recover()
    err := r.(error)
    if err == nil {
        return
    }
    fmt.Println(err.Error())
}

func foo() {
    defer errorHandler()
    smallSlice := []int{1, 0, 1}
    smallSlice[10] = 1
}

func main() {
    foo()
    fmt.Println("recovery, end of main")
}

输出:



是否有一些示例,其中运行时错误将使程序崩溃而又没有可恢复的 panic ?

最佳答案

首先更改您的errorHandler(),因为如果没有 panic ,则r将是nil,因此类型声明将失败:

func errorHandler() {
    if r := recover(); r != nil {
        fmt.Println(r)
    }
}

现在,这里是一些带有代码的示例,这些代码会产生无法恢复的运行时错误:

1.内存不足:
func foo() {
    defer errorHandler()
    _ = make([]int64, 1<<40) // You have to change the size on 32-bit systems
}

2.并发映射读写

有关详细信息,请参见How to recover from concurrent map writes?,例如,请参见Can marshalling a map[string]string to json return an error?
func foo() {
    defer errorHandler()
    m := map[string]int{}

    go func() {
        for {
            m["x"] = 1
        }
    }()
    for {
        _ = m["x"]
    }
}

3.堆栈内存耗尽

有关详细信息,请参见Does Go have an "infinite call stack" equivalent?
func foo() {
    defer errorHandler()

    var f func(a [1000]int64)
    f = func(a [1000]int64) {
        f(a)
    }
    f([1000]int64{})
}

4.尝试将nil函数作为goroutine启动
func foo() {
    defer errorHandler()
    var f func()
    go f()
}

5.所有goroutine都在 sleep 中-死锁

标题说明了一切。这是阻止当前goroutine的简单代码,但是,如果您启动了其他goroutine,则显然不会遇到崩溃。在此处查看其他示例:Go project's main goroutine sleep forever?
func foo() {
    defer errorHandler()
    select {}
}

6.线程限制用尽

如果您的goroutine被IO操作阻塞,则可能会启动新线程来执行其他goroutine。最大线程数显然有一个限制,如果达到最大线程数,您的应用程序将崩溃。

关于go - Go中是否可以恢复所有运行时错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57486620/

10-13 02:50