繁体   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