GoLang - catch panic 避免主系統錯誤
在這幾篇,會以 Go 語言的入門基礎進行逐步說明,本篇針對 catch panic 進行說明
在 Go 語言並沒有 try catch 的機制,在系統運行過程,若發生 panic 則會導致整個系統崩壞。
如何解決 panic 導致崩潰
在這裡舉前面監聽多 channel 的例子,在 goroutine 運行過程,若發生錯誤,同樣會連帶造成主程式錯誤,
因此在運行時,可以透過 recover 來捕獲 panic 的行為,例如:
func writeData(intChan chan int) {
//catch panic
defer func() {
if err := recover(); err != nil {
fmt.Println("WriteData error happened:", err)
}
}()
for i := 1; i <= 3; i++ {
intChan <- i
fmt.Printf("writeData = %v\n", i)
}
close(intChan)
}
接著,在這部分我們刻意在過程中引發 panic
func writeData2(secChan chan int) {
//catch panic
defer func() {
if err := recover(); err != nil {
fmt.Println("WriteData2 error happened:", err)
}
}()
for i := 1; i <= 3; i++ {
secChan <- i
fmt.Printf("writeSecData ==> %v\n", i)
var testErrorMap map[int]string
testErrorMap[0] = "error happened"
}
close(secChan)
}
透過捕捉 panic 可以讓錯誤發生時,不會導致系統崩壞,以下是輸出內容:
Nothine input
writeSecData ==> 1
ReadSecData ==> 1
ReadData = 1
Nothine input
Nothine input
Nothine input
WriteData2 error happened: assignment to entry in nil map
writeData = 1
writeData = 2
writeData = 3
ReadData = 2
ReadData = 3
timeout
最後,附上最終完整內容
package main
import (
"fmt"
"time"
)
func writeData(intChan chan int) {
//catch panic
defer func() {
if err := recover(); err != nil {
fmt.Println("WriteData error happened:", err)
}
}()
for i := 1; i <= 3; i++ {
intChan <- i
fmt.Printf("writeData = %v\n", i)
}
close(intChan)
}
func writeData2(secChan chan int) {
//catch panic
defer func() {
if err := recover(); err != nil {
fmt.Println("WriteData2 error happened:", err)
}
}()
for i := 1; i <= 3; i++ {
secChan <- i
fmt.Printf("writeSecData ==> %v\n", i)
var testErrorMap map[int]string
testErrorMap[0] = "error happened"
}
close(secChan)
}
func main() {
intChan := make(chan int, 3)
secChan := make(chan int, 10)
go writeData(intChan)
go writeData2(secChan)
//設定逾時
timeout := time.After(5 * time.Second)
Loop:
for {
select {
case v, ok := <-intChan:
if ok {
fmt.Printf("ReadData = %v\n", v)
}
case n, ok := <-secChan:
if ok {
fmt.Printf("ReadSecData ==> %v\n", n)
}
case <-timeout:
fmt.Println("timeout")
break Loop
default:
//在這裡可決定是否結束
fmt.Printf("Nothine input\n")
}
}
fmt.Println("End")
}