一尘不染

呼叫者如何从子Goroutine的恐慌中恢复

go

我曾经认为,如果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开始恐慌,调用者的延迟恢复机制将无济于事。整个程序仍然无效。

所以为什么?理论上,调用者功能仍在运行。当出现紧急情况时,调用者的延迟功能应起作用(包括恢复)。


阅读 186

收藏
2020-07-02

共1个答案

一尘不染

规范说

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

因为fun2是在goroutine中执行的顶层函数,fun2并且无法从紧急情况中恢复,所以程序在发生fun2紧急情况时会终止。

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

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

2020-07-02