首页  >  文章  >  后端开发  >  为什么 `recover()` 无法处理 Go 例程中的恐慌?

为什么 `recover()` 无法处理 Go 例程中的恐慌?

Susan Sarandon
Susan Sarandon原创
2024-11-06 20:01:03799浏览

Why Does `recover()` Fail to Handle Panics in Go Routines?

处理 Go 例程中的恐慌

Go 例程在 Go 程序中提供并发性,但这些例程中的恐慌可能会带来挑战。为了从恐慌中恢复,通常使用recover()函数。然而,在某些情况下,recover() 在 Goroutine 中无法按预期运行。

了解 Go 例程中恢复失败

考虑以下代码块:

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
}

此代码尝试使用 main 函数中的延迟函数从 goroutine 中的恐慌中恢复。然而,它未能挽回恐慌。相反,以下代码块按预期运行:

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
}

解决恢复问题

理解这种行为的关键在于 goroutine 的本质。 receive() 只能从调用它的同一 goroutine 中发生的恐慌中恢复。来自 Go 博客:

该过程继续在堆栈中向上进行,直到当前 goroutine 中的所有函数都返回,此时程序崩溃

要处理 goroutine 中的恐慌,需要使用goroutine 本身内的延迟恢复函数。

func handle(done chan int64) {
    defer func() {
        if r := recover(); r != nil {
            if _, ok := r.(error); ok {
                fmt.Println("Recovered in goroutine")
            }
        }
    }()

    var a *int64
    a = nil

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

通过将恢复函数放置在 goroutine 内,可以拦截恐慌并进行适当的处​​理。

以上是为什么 `recover()` 无法处理 Go 例程中的恐慌?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn