panic和recover用于将异常的处理和正常的业务逻辑代码解耦,如果没有recover,panic时程序将会异常终止。panic只会调用当前协程的defer,从而也只会调用当前协程的recover。
- panic调用defer的顺序
package main
import "fmt"
func defer1() {
fmt.Println("defer1")
}
func defer2() {
fmt.Println("defer2")
}
func main() {
defer defer1()
defer defer2()
fmt.Println("in main")
panic("panic occured")
}
输出
in main
defer2
defer1
panic: panic occured
goroutine 1 [running]:
main.main()
C:/Users/wangfeng/go/src/awesomeProject/panic.go:17 +0xcb
exit status 2
panic之前按照出栈顺序调用defer。
- panic只会调用当前协程的defer
package main
import (
"fmt"
"sync"
)
func defer1() {
fmt.Println("defer1")
}
func defer2() {
fmt.Println("defer2")
}
func goroutine(wg *sync.WaitGroup) {
defer wg.Done()
defer defer2()
fmt.Println("i am goroutine.")
panic("panic occured in goroutine")
}
func main() {
var wg sync.WaitGroup
defer defer1()
fmt.Println("in main")
wg.Add(1)
go goroutine(&wg)
wg.Wait()
}
输出
C:\Users\wangfeng\go\src\awesomeProject>go run panic.go
in main
i am goroutine.
defer2
panic: panic occured in goroutine
goroutine 6 [running]:
main.goroutine(0xc00000a0b0)
C:/Users/wangfeng/go/src/awesomeProject/panic.go:20 +0xe5
created by main.main
C:/Users/wangfeng/go/src/awesomeProject/panic.go:29 +0xf5
exit status 2
panic返回之前,只会调用当前协程的defer。没有recover时,panic会退出整个进程。
- panic和recover
package main
import (
"fmt"
"sync"
)
func defer1() {
fmt.Println("defer1")
}
func defer2() {
fmt.Println("defer2")
if err:=recover(); err!=nil {
fmt.Println("in recover()", err)
}
}
func goroutine(wg *sync.WaitGroup) {
defer wg.Done()
defer defer2()
fmt.Println("i am goroutine.")
panic("panic occured in goroutine")
}
func main() {
var wg sync.WaitGroup
defer defer1()
fmt.Println("in main")
wg.Add(1)
go goroutine(&wg)
wg.Wait()
}
输出
C:\Users\wangfeng\go\src\awesomeProject>go run panic.go
in main
i am goroutine.
defer2
in recover() panic occured in goroutine
defer1
recover会让进程正常终止,类似try catch。
- panic之后的不会执行
package main
import "fmt"
func recover1() {
if err:=recover(); err!=nil {
fmt.Println("recover1", err)
}
}
func recover2() {
if err:=recover(); err!=nil {
fmt.Println("recover2", err)
}
}
func worker(){
defer recover2()
fmt.Println("i am worker")
panic("worker error")
}
func main(){
defer recover1()
panic("main error")
go worker()
}
输出:
recover1 main error