处理 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中文网其他相关文章!