Go在协程中正确捕获pinic

众所周知,在golang中拆改使用go关键字即可快捷的开启一个异步协程,例如:

package main

func main() {
    go hello()
}

func hello() {
    println("Hello, World!")
}

那么一般我们捕获程序异常(pinic)是在调用前使用defer捕获异常后进行操作

package main

import "errors"

func main() {
    defer func() {
        if err := recover(); err != nil {
            // 这里可以进行日志记录等操作
            println(err.(error).Error())
        }
    }()

    hello()

    println("bye!")

    select {}
}

func hello() {
    println("Hello, World!")
    panic(errors.New("hello panic"))
}

但是一旦在协程中pinic则main方法的defer将失去作用,比如将以上代码的hello调用前加上go关键字。

会发现整个程序都将停止运行,所以我们需要在会用到协程的方法内使用defer捕获协程内可能出现的pinic:

package main

import (
    "errors"
    "time"
)

func main() {
    defer func() {
        if err := recover(); err != nil {
            // 这里可以进行日志记录等操作
            println(err.(error).Error())
        }
    }()

    go hello()

    println("bye!")

    select {}
}

func hello() {
    defer func() {
        if err := recover(); err != nil {
            // 这里可以进行日志记录等操作
            println("协程内异常:" + err.(error).Error())
        }

        // 延迟1秒重启
        time.Sleep(time.Second)
        go hello()
    }()
    println("Hello, World!")

    panic(errors.New("hello panic"))
}