[英]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.