從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中文網其他相關文章!