[英]How to wait for a panicking goroutine?
A common way to wait for a goroutine is to use a *sync.WaitGroup
:等待 goroutine 的常用方法是使用
*sync.WaitGroup
:
func main() {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
// Long running task
}()
wg.Wait()
}
No problems here.这里没有问题。 However, what about this:
但是,这又如何:
func main() {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
// Long running task
panic("Something unexpected happened.")
}()
wg.Wait()
}
In this case, when wg.Done()
is called, I believe main()
could exit without details of panic()
ever being written to stdout
/ stderr
.在这种情况下,当
wg.Done()
被调用时,我相信main()
可以退出,而不会将panic()
细节写入stdout
/ stderr
。 Is this true and if yes, how might I prevent it from happening?这是真的吗?如果是,我该如何防止它发生?
The panic
will kill the process regardless, because no one is recovering from it.无论如何,
panic
都会杀死这个过程,因为没有人能从中恢复。 If you want to recover from panics in a goroutine, you must have recover
wrapping the call stack in the same goroutine.如果你想从一个够程恐慌中恢复过来,你必须
recover
包裹在同一个够程调用堆栈。
wg.Done
will be called in this case, by the defer
statement.在这种情况下,将通过
defer
语句调用wg.Done
。 But the process may die before the main goroutine finishes the wg.Wait
anyway.但是进程可能会在主 goroutine 完成
wg.Wait
之前wg.Wait
。
@Eli Bendersky was right. @Eli Bendersky 是对的。
Reference src/builtin/builtin.go参考src/builtin/builtin.go
The panic built-in function stops normal execution of the current goroutine.
panic 内置函数停止当前 goroutine 的正常执行。 When a function F calls panic, normal execution of F stops immediately.
当函数 F 调用 panic 时,F 的正常执行会立即停止。 Any functions whose execution was deferred by F are run in the usual way, and then F returns to its caller.
任何被 F 推迟执行的函数都以通常的方式运行,然后 F 返回给它的调用者。 To the caller G, the invocation of F then behaves like a call to panic, terminating G's execution and running any deferred functions.
对于调用者 G 来说,F 的调用就像调用 panic,终止 G 的执行并运行任何延迟函数。 This continues until all functions in the executing goroutine have stopped, in reverse order.
这一直持续到正在执行的 goroutine 中的所有函数都以相反的顺序停止。 At that point, the program is terminated and the error condition is reported, including the value of the argument to panic.
此时,程序终止并报告错误条件,包括 panic 的参数值。 This termination sequence is called panicking and can be controlled by the built-in function recover.
这种终止序列称为恐慌,可以由内置函数恢复控制。
after panic
, defer
func will be called.在
panic
之后, defer
func 将被调用。
Check this in playground: https://play.golang.org/p/yrXkEbE1Af7在操场上检查这个: 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()
}
Output输出
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
Then your second question, "how to prevent that?"然后你的第二个问题,“如何防止?”
As metioned before, you can recover
after panic
如前所述,您可以在
panic
后recover
Playground: https://play.golang.org/p/76pPrCVYN8u游乐场: 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)
}
}
Output输出
Something unexpected happened.
0
1
2
3
4
5
6
7
8
9
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.