处理 go 例程中的恐慌
Handling panics in go routines
我了解使用处理紧急恢复。但是在go routine
出现panic时,下面的block无法恢复
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
}
如何从 go 例程中出现的恐慌中恢复。这是 playground 的 link:https://play.golang.org/p/lkvKUxMHjhi
仅当从调用 panic 的同一个 goroutine 调用时,恢复才有效。来自 Go 博客:
The process continues up the stack until all functions in the current
goroutine have returned, at which point the program crashes
您必须在 goroutine 中进行延迟恢复。
https://blog.golang.org/defer-panic-and-recover
文档/规范也包含相同的内容:
While executing a function F, an explicit call to panic or a run-time
panic terminates the execution of F. Any functions deferred by F are
then executed as usual. Next, any deferred functions run by F's caller
are run, and so on up to any deferred by the top-level function in the
executing goroutine. At that point, the program is terminated and the
error condition is reported, including the value of the argument to
panic. This termination sequence is called panicking
我用下面的方法来处理这种情况,效果和预期的一样。
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
}
我了解使用处理紧急恢复。但是在go routine
出现panic时,下面的block无法恢复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
}
如何从 go 例程中出现的恐慌中恢复。这是 playground 的 link:https://play.golang.org/p/lkvKUxMHjhi
仅当从调用 panic 的同一个 goroutine 调用时,恢复才有效。来自 Go 博客:
The process continues up the stack until all functions in the current goroutine have returned, at which point the program crashes
您必须在 goroutine 中进行延迟恢复。
https://blog.golang.org/defer-panic-and-recover
文档/规范也包含相同的内容:
While executing a function F, an explicit call to panic or a run-time panic terminates the execution of F. Any functions deferred by F are then executed as usual. Next, any deferred functions run by F's caller are run, and so on up to any deferred by the top-level function in the executing goroutine. At that point, the program is terminated and the error condition is reported, including the value of the argument to panic. This termination sequence is called panicking
我用下面的方法来处理这种情况,效果和预期的一样。
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
}