【问题标题】:How does a caller function to recover from child goroutine's panics调用者如何从子 goroutine 的恐慌中恢复
【发布时间】:2018-05-28 05:57:24
【问题描述】:

我曾经认为如果调用者在恐慌之前完成,goroutine 中的恐慌会杀死程序(延迟恢复没有帮助,因为此时还没有发生恐慌),

直到我尝试了以下代码:



    func fun1() {
        fmt.Println("fun1 started")
        defer func() {
            if err := recover(); err != nil {
                fmt.Println("recover in func1")
            }
        }()

        go fun2()

        time.Sleep(10 * time.Second) // wait for the boom!
        fmt.Println("fun1 ended")
    }

    func fun2() {
        fmt.Println("fun2 started")

        time.Sleep(5 * time.Second)
        panic("fun2 booom!")

        fmt.Println("fun2 ended")
    }

我发现无论调用者函数完成与否,如果它启动的 goroutines 恐慌,调用者的延迟恢复机制将无济于事。整个程序还是死了。

那么,为什么?理论上调用者函数仍在运行。当恐慌发生时,调用者的延迟函数应该可以工作(包括恢复)。

【问题讨论】:

    标签: go goroutine recover panic


    【解决方案1】:

    specification says

    在执行函数 F 时,显式调用 panic 或运行时 panic 会终止 F 的执行。任何被 F 延迟的函数都会照常执行。接下来,运行由 F 的调用者运行的任何延迟函数,依此类推,直到执行 goroutine 中的顶级函数延迟。此时,程序终止并报告错误情况,包括 panic 的参数值。这种终止序列称为恐慌。

    因为fun2是goroutine中执行的顶级函数,而fun2没有从恐慌中恢复,所以当fun2发生恐慌时程序终止。

    当执行fun2 的goroutine 发生恐慌时,不会调用fun1 中的延迟调用。

    一个 goroutine 无法从另一个 goroutine 的恐慌中恢复。

    【讨论】:

    • 所以这意味着调用者的延迟恢复是在子 goroutine 中恐慌后调用的,但是其中的 recover() 不能得到任何非 nil 错误,因为 A gotourine 无法恢复来自另一个 goroutine 的恐慌 --- 这是有道理的。
    • fun1 中的延迟函数fun2 发生恐慌时调用。因此fun1 无法从fun2 的恐慌中恢复。
    • 但是刚才提到的规范:接下来,F的调用者运行的任何延迟函数都会运行
    • ... 等等,直到执行 goroutine 中的顶级函数延迟。
    • @DaveWu 我认为func1 不是func2 的来电者。 func2 在不同的 go 例程中运行。
    【解决方案2】:

    您可以在 fun2() 中使用 runtime.Goexit() 而不是在 fun1() 中恢复

    Goexit 终止调用它的 goroutine。没有其他 goroutine 受影响。

    类似

    func fun2() {
        defer func() {
            if err := recover(); err != nil {
                fmt.Println("Do some cleanup and teardown")
                runtime.Goexit() //Here
            }
        }
        ...
    }
    

    【讨论】:

    • 但是请注意,这将阻止延迟调用在 fun2() 的调用者中运行,即使它们在同一个 goroutine 中。例如,如果调用路径是fun1() -> go fun3() -> fun2(),则在fun2() 中调用runtime.Goexit(),即使在延迟恢复中,也会阻止fun3() 中的任何延迟调用运行.
    猜你喜欢
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    相关资源
    最近更新 更多