等待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
。这是真的吗?如果是,我如何防止它发生?
答案 0 :(得分:3)
111 Error in parsing request XML:Error: Datatype error: In element 'PhoneNumber' : Value '' does not match regular expression facet '.*[^\s].*'.. at line 36, column 35
将终止该进程,因为没有人从中恢复。如果要从goroutine中的紧急情况中恢复,则必须panic
将调用堆栈包装在同一个goroutine中。
recover
语句调用 wg.Done
。但是无论如何,该过程可能在主goroutine完成defer
之前就死了。
答案 1 :(得分:0)
@Eli Bendersky是正确的。
panic内置函数停止当前的正常执行 goroutine。当函数F调用恐慌时,F的正常执行停止 立即。在F中推迟执行的任何函数 按照通常的方式,然后F返回其调用方。对于呼叫者G, 然后,调用F就像调用恐慌一样,终止G的 执行并运行任何延迟的功能。这一直持续到所有 正在执行的goroutine中的函数已按相反的顺序停止。在 这时,程序终止,并报告错误情况, 包括引起恐慌的论点的价值。此终止顺序 称为恐慌,可以通过内置功能进行控制 恢复。
在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
然后您的第二个问题,“如何预防?”
如前所述,您可以在recover
之后panic
游乐场: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