簡體   English   中英

如何等待一個恐慌的 goroutine?

[英]How to wait for a panicking goroutine?

等待 goroutine 的常用方法是使用*sync.WaitGroup

func main() {
    wg := &sync.WaitGroup{}
    wg.Add(1)
    go func() {
        defer wg.Done()
        // Long running task
    }()
    wg.Wait()
}

這里沒有問題。 但是,這又如何:

func main() {
    wg := &sync.WaitGroup{}
    wg.Add(1)
    go func() {
        defer wg.Done()
        // Long running task
        panic("Something unexpected happened.")
    }()
    wg.Wait()
}

在這種情況下,當wg.Done()被調用時,我相信main()可以退出,而不會將panic()細節寫入stdout / stderr 這是真的嗎?如果是,我該如何防止它發生?

無論如何, panic都會殺死這個過程,因為沒有人能從中恢復。 如果你想從一個夠程恐慌中恢復過來,你必須recover包裹在同一個夠程調用堆棧。

在這種情況下,將通過defer語句調用wg.Done 但是進程可能會在主 goroutine 完成wg.Wait之前wg.Wait

@Eli Bendersky 是對的。

參考src/builtin/builtin.go

panic 內置函數停止當前 goroutine 的正常執行。 當函數 F 調用 panic 時,F 的正常執行會立即停止。 任何被 F 推遲執行的函數都以通常的方式運行,然后 F 返回給它的調用者。 對於調用者 G 來說,F 的調用就像調用 panic,終止 G 的執行並運行任何延遲函數。 這一直持續到正在執行的 goroutine 中的所有函數都以相反的順序停止。 此時,程序終止並報告錯誤條件,包括 panic 的參數值。 這種終止序列稱為恐慌,可以由內置函數恢復控制。

panic之后, defer func 將被調用。

在操場上檢查這個: https : //play.golang.org/p/yrXkEbE1Af7

package main

import (
    "sync"
    "fmt"
)

func main() {
    wg := &sync.WaitGroup{}
    wg.Add(1)
    go func() {
        defer func(){
            fmt.Println("expected to be called after panic")
            wg.Done()
        }()
        // Long running task
        panic("Something unexpected happened.")
    }()
    wg.Wait()
}

輸出

expected to be called after panic
panic: Something unexpected happened.

goroutine 5 [running]:
main.main.func1(0x416020, 0x0)
    /tmp/sandbox946785562/main.go:17 +0x60
created by main.main
    /tmp/sandbox946785562/main.go:11 +0x80

然后你的第二個問題,“如何防止?”

如前所述,您可以在panicrecover

游樂場: https : //play.golang.org/p/76pPrCVYN8u

package main

import (
    "sync"
    "fmt"
)

func main() {
    wg := &sync.WaitGroup{}
    wg.Add(1)
    go func() {
        defer func(){
            if x:=recover();x!=nil{
                fmt.Printf("%+v\n",x)
            }
            wg.Done()
        }()
        // Long running task
        panic("Something unexpected happened.")
    }()
    wg.Wait()
    for i:=0;i<10;i++{
        fmt.Println(i)
    }
}

輸出

Something unexpected happened.
0
1
2
3
4
5
6
7
8
9

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM