在例程中处理恐慌

时间:2018-05-18 10:14:42

标签: go recovery panic

我理解使用处理恐慌恢复。但是,当在例行程序中出现恐慌时,以下块无法恢复

func main() {
    done := make(chan int64)
    defer fmt.Println("Graceful End of program")
    defer func() {
     r := recover()
     if _, ok := r.(error); ok {
        fmt.Println("Recovered")
     }
    }()

    go handle(done)
    for {
        select{
        case <- done:
        return
        }
    } 
}

func handle(done chan int64) {
    var a *int64
    a = nil

    fmt.Println(*a)
    done <- *a
}

但是下面的块能够按预期执行

func main() {
    done := make(chan int64)
    defer fmt.Println("Graceful End of program")
    defer func() {
     r := recover()
     if _, ok := r.(error); ok {
        fmt.Println("Recovered")
     }
    }()

    handle(done)
    for {
        select{
        case <- done:
        return
        }
    } 
}

func handle(done chan int64) {
    var a *int64
    a = nil

    fmt.Println(*a)
    done <- *a
}

如何从日常生活中出现的恐慌中恢复过来。以下是操场的链接:https://play.golang.org/p/lkvKUxMHjhi

2 个答案:

答案 0 :(得分:6)

恢复仅在调用恐慌时从同一goroutine调用时有效。来自golang博客:

  

进程继续向上移动,直到当前所有函数   goroutine已经返回,此时程序崩溃

你必须在goroutine中进行延迟恢复。

https://blog.golang.org/defer-panic-and-recover

docs / spec也包括相同的内容:

  

执行函数F时,显式调用panic或运行时   panic终止F的执行。任何由F推迟的函数都是   然后像往常一样执行。接下来,任何延迟函数由F的调用者运行   运行,依此类推,直至由顶级函数推迟   执行goroutine 。那时,程序终止了   报告错误条件,包括参数的值   恐慌。此终止序列称为恐慌

https://golang.org/ref/spec#Handling_panics

答案 1 :(得分:0)

我使用以下方式来处理这种情况,它按预期工作。

package main

import (
    "fmt"
    "time"
)

func main() {
    defer fmt.Println("Graceful End of program")
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered:", r)
        }
    }()

    done := make(chan int64)
    var panicVar interface{}

    go handle(done, &panicVar)

WAIT:
    for {
        select {
        case <-done:
            break WAIT // break WAIT: goroutine exit normally
        default:
            if panicVar != nil {
                break WAIT // break WAIT: goroutine exit panicked
            }

            // wait for goroutine exit
        }

        time.Sleep(1 * time.Microsecond)
    }

    if panicVar != nil {
        panic(panicVar) // panic again
    }
}

func handle(done chan int64, panicVar *interface{}) {
    defer func() {
        if r := recover(); r != nil {
            // pass panic variable outside
            *panicVar = r
        }
    }()

    var a *int64
    a = nil

    fmt.Println(*a)
    done <- *a
}

游乐场链接:https://play.golang.org/p/t0wXwB02pa3