程序中启用多个Goroutine,如果其中一个Goroutine因为一些隐式的运行时错误将调用panic,如果没有合适的处理,将导致所有的Goroutine终止。
严重故障 panic
- Go语言提供了一个内置的panic方法,用来创建一个运行时错误并结束当前程序。
- 它将立刻中断当前函数的执行,并展开当前Goroutine的调用栈,依次执行之前注册的defer函数。当栈展开操作达到该Goroutine栈顶端时,程序将终止。
- 对于一些隐式的运行时错误,如切片索引越界、类型断言错误等情形下,panic方法就会被调用。)
恢复 revocer
- 对于panic,可以使用Go的内建recover方法重新获得Goroutine的控制权,并将程序恢复到正常执行的状态。
- 调用recover方法会终止栈展开操作并返回之前传递给panic方法的那个参数。由于在栈展开过程中,只有defer函数会被执行,因此recover的调用必须置于defer函数内才有效。
Goroutine中panic导致整个程序终止
当在一个Goroutine中发生panic调用时会终止整个程序,如下,创建多个Goroutine,由于panic导致整个程序崩溃,其它Goroutine没有执行
package main
import (
"fmt"
)
func test(n int, c chan int) {
defer func() {
fmt.Printf("test: %d\n", n)
c <- n
}()
panic(fmt.Sprintf("panic: %d", n))
}
func main() {
c := make(chan int, 0)
for i := 0; i < 10; i++ {
go test(i, c)
}
for i := 0; i < 10; i++ {
<-c
}
}
打印报错:
test: 9
test: 1
panic: panic: 9
goroutine 14 [running]:
main.test(0x9, 0xc000062060)
/Users/chicheng/go/src/work/main.go:16 +0x106
created by main.main
/Users/chicheng/go/src/work/main.go:23 +0x6f
exit status 2
Goroutine中recover恢复正常执行
recover在panic执行后会获得Goroutine控制权,其它Goroutine可以继续执行
package main
import (
"fmt"
)
func test(n int, c chan int) {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
c <- n
}()
panic(fmt.Sprintf("panic: %d", n))
}
func main() {
c := make(chan int, 0)
for i := 0; i < 10; i++ {
go test(i, c)
}
for i := 0; i < 10; i++ {
<-c
}
}
打印结果:
panic: 9
panic: 3
panic: 1
panic: 0
panic: 4
panic: 6
panic: 7
panic: 2
panic: 8
panic: 5