Panic and recover use
Go does not support the traditional try…catch…finally exception, because Go designers believe that mixing exceptions with control structures can easily mess up the code. In Go, designers recommend using multi-value returns to return errors. In case of real exceptions (such as the divisor is 0). Only use the Exception introduced in Go: defer, panic, recover.
The usage scenarios of these exceptions can be described in this simple way: a panic exception can be thrown in Go, and then the exception is caught through recover in defer, and then processed normally
Example of usage
package main import "fmt" func main(){ ("c") defer func(){ // Defer must be declared first, otherwise the panic exception cannot be caught ("d") if err:=recover();err!=nil{ (err) // The err here is actually the content passed in by panic, 55 } ("e") }() f() //Start call f ("f") //The following code will not be executed again after starting here} func f(){ ("a") panic("Exception information") ("b") //The following code will not be executed again after starting here ("f") }
Output result:
c
a
d
Exception information
e
Notice
- Use recover to process panic instructions, recover needs to be defined within the defer anonymous function
- Defer needs to be declared before panic, otherwise recover cannot capture panic when panic
- If panic is not recovered, the program will crash directly
subfunction panic main function recover
func TestPanic(t *) { defer func() { if err := recover(); err != nil { println("recovered") } }() subFun() subFun() } func subFun() { println("subFun") panic("subFun panic") }
The output result is as follows, the code after the first sunFun will not be executed
subFun
recovered
child coroutine panic main function recover
func subFun(i int) { ("subFun,i=", i) panic("subFun panic") } func TestSubGoPanic(t *) { defer func() { if err := recover(); err != nil { println("recovered2") } }() go subFun(3) subFun(4) println("finish") }
result
subFun,i= 4
recovered2
subFun,i= 3
--- PASS: TestSubGoPanic (0.00s)
panic: subFun panic
goroutine 21 [running]:
/base/(0x0?)
/Users/albert/file/code/go/zh/gotest/base/err/panic_test.go:34 +0x89
created by /base/
/Users/albert/file/code/go/zh/gotest/base/err/panic_test.go:43 +0x46
Recover will execute, but the program crashes
Summary of use
If panic and recover occur in the same coroutine, then recover is catchable. If panic and recover occur in different coroutines, then recover is not catchable
That is, which coroutine has panic, and which coroutine must have recovery, otherwise the entire program will crash
Some worries about using panic
performance
It is very common to encounter panic when developing using Golang. However, the impact of panic on performance is relatively small, especially in actual use.
First, Golang maintains a panic heap at runtime to store panic objects in the stack. When a program encounters panic, the panic object is added to the panic heap. The size of the panic heap is limited. If there are too many objects in the heap, it may cause the panic heap to overflow, which will affect the performance of the program.
Performance comparison
func BenchmarkSubFunWithError(b *) { for i := 0; i < ; i++ { go subFunWithError(i) } } func BenchmarkSubFunWithRecover(b *) { for i := 0; i < ; i++ { go subFunWithRecover(i) } } func subFunWithRecover(i int) { //("subFun,i=", i) defer func() { if error := recover(); error != nil { //println("subFunWithRecover_recovered") } }() () panic("subFun panic") } func subFunWithError(i int) error { //("subFun,i=", i) () return ("subFunWithError") } BenchmarkSubFunWithError-12 673920 1992 ns/op 489 B/op 3 allocs/op BenchmarkSubFunWithRecover-12 1000000 1229 ns/op 240 B/op 2 allocs/op
Instead, using panic has better performance?
Safety
Another thing that is more worrying is that panic can easily cause crashes, but as shown above, as long as recovery is done in the main method, each go coroutine uses the encapsulated method with recovery to call it, there will be no problem in fact.
This is the article about Golang exception handling elegantly controlling and handling exceptions. For more related Golang exception handling content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!