程序中啓用多個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