[英]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 是對的。
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
然后你的第二個問題,“如何防止?”
如前所述,您可以在panic
后recover
游樂場: 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.