从 Go 中的子 Goroutine 恐慌中恢复
在最近的编程工作中,一个基本假设受到了挑战:调用者函数的能力从子 goroutine 的恐慌中恢复过来。尽管传统观点认为并非如此,但我们发现,当子 goroutine 陷入恐慌时,调用者的延迟恢复机制无法阻止整个程序终止。
为了说明这种令人费解的行为,请考虑以下代码:
<code class="go">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") }</code>
有趣的是,无论 fun1 在 fun2 发生恐慌之前还是之后结束,fun1 中的延迟恢复机制都无效,导致程序立即终止。
背后的原因失败
Go 规范对这种非常规行为进行了澄清:
在执行函数 F 时,对恐慌的显式调用或运行时恐慌会终止 F 的执行。 F 推迟的函数然后照常执行。 接下来,由 F 的调用者运行的任何延迟函数都会运行,依此类推,直到执行 Goroutine 中的顶级函数所延迟的任何函数。 此时,程序终止并报告错误情况,包括panic的参数值。
在这种情况下,fun2代表在其各自的goroutine中执行的顶级函数。由于 fun2 缺乏恢复机制,程序会在发生恐慌时终止,而忽略 fun1 或其前辈中任何延迟的恢复尝试。
这种行为强调了一个关键区别:goroutine 无法从源自以下的恐慌中恢复:一个单独的 goroutine。因此,fun1 中的延迟恢复变得徒劳,因为 fun2 中的恐慌有效地终止了 goroutine 以及任何后续的恢复工作。
以上是调用者函数可以从 Go 子 Goroutines 中的 Panic 中恢复吗?的详细内容。更多信息请关注PHP中文网其他相关文章!