呼叫者如何从儿童goroutine的恐慌中恢复

时间:2017-12-14 07:51:41

标签: go goroutine recover panic

我曾经认为,如果调用者在恐慌之前完成,那么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它开始恐慌,调用者的延迟恢复机制将无济于事。整个计划仍然没有。

那么,为什么?从理论上讲,调用者函数仍在运行。当恐慌发生时,呼叫者的延期功能应该起作用(包括恢复)。

2 个答案:

答案 0 :(得分:4)

specification says

  

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

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

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

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

答案 1 :(得分:0)

您可以在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
        }
    }
    ...
}