新聞中心
Go語言的類型系統(tǒng)會在編譯時捕獲很多錯誤,但有些錯誤只能在運(yùn)行時檢查,如數(shù)組訪問越界、空指針引用等,這些運(yùn)行時錯誤會引起宕機(jī)。

宕機(jī)不是一件很好的事情,可能造成體驗(yàn)停止、服務(wù)中斷,就像沒有人希望在取錢時遇到 ATM 機(jī)藍(lán)屏一樣,但是,如果在損失發(fā)生時,程序沒有因?yàn)殄礄C(jī)而停止,那么用戶將會付出更大的代價,這種代價可以是金錢、時間甚至生命,因此,宕機(jī)有時也是一種合理的止損方法。
一般而言,當(dāng)宕機(jī)發(fā)生時,程序會中斷運(yùn)行,并立即執(zhí)行在該 goroutine(可以先理解成線程)中被延遲的函數(shù)(defer 機(jī)制),隨后,程序崩潰并輸出日志信息,日志信息包括 panic value 和函數(shù)調(diào)用的堆棧跟蹤信息,panic value 通常是某種錯誤信息。
對于每個 goroutine,日志信息中都會有與之相對的,發(fā)生 panic 時的函數(shù)調(diào)用堆棧跟蹤信息,通常,我們不需要再次運(yùn)行程序去定位問題,日志信息已經(jīng)提供了足夠的診斷依據(jù),因此,在我們填寫問題報告時,一般會將宕機(jī)和日志信息一并記錄。
雖然Go語言的 panic 機(jī)制類似于其他語言的異常,但 panic 的適用場景有一些不同,由于 panic 會引起程序的崩潰,因此 panic 一般用于嚴(yán)重錯誤,如程序內(nèi)部的邏輯不一致。任何崩潰都表明了我們的代碼中可能存在漏洞,所以對于大部分漏洞,我們應(yīng)該使用Go語言提供的錯誤機(jī)制,而不是 panic。
手動觸發(fā)宕機(jī)
Go語言可以在程序中手動觸發(fā)宕機(jī),讓程序崩潰,這樣開發(fā)者可以及時地發(fā)現(xiàn)錯誤,同時減少可能的損失。
Go語言程序在宕機(jī)時,會將堆棧和 goroutine 信息輸出到控制臺,所以宕機(jī)也可以方便地知曉發(fā)生錯誤的位置,那么我們要如何觸發(fā)宕機(jī)呢,示例代碼如下所示:
package main
func main() {
panic("crash")
}代碼運(yùn)行崩潰并輸出如下:
panic: crash
goroutine 1 [running]:
main.main()
D:/code/main.go:4 +0x40
exit status 2
以上代碼中只用了一個內(nèi)建的函數(shù) panic() 就可以造成崩潰,panic() 的聲明如下:
func panic(v interface{}) //panic() 的參數(shù)可以是任意類型的。
在運(yùn)行依賴的必備資源缺失時主動觸發(fā)宕機(jī)
regexp 是Go語言的正則表達(dá)式包,正則表達(dá)式需要編譯后才能使用,而且編譯必須是成功的,表示正則表達(dá)式可用。
編譯正則表達(dá)式函數(shù)有兩種,具體如下:
1) func Compile(expr string) (*Regexp, error)
編譯正則表達(dá)式,發(fā)生錯誤時返回編譯錯誤同時返回 Regexp 為 nil,該函數(shù)適用于在編譯錯誤時獲得編譯錯誤進(jìn)行處理,同時繼續(xù)后續(xù)執(zhí)行的環(huán)境。
2) func MustCompile(str string) *Regexp
當(dāng)編譯正則表達(dá)式發(fā)生錯誤時,使用 panic 觸發(fā)宕機(jī),該函數(shù)適用于直接使用正則表達(dá)式而無須處理正則表達(dá)式錯誤的情況。
MustCompile 的代碼如下:
func MustCompile(str string) *Regexp {
regexp, error := Compile(str)
if error != nil {
panic(`regexp: Compile(` + quote(str) + `): ` + error.Error())
}
return regexp
}代碼說明如下:
- 第 1 行,編譯正則表達(dá)式函數(shù)入口,輸入包含正則表達(dá)式的字符串,返回正則表達(dá)式對象。
- 第 2 行,Compile() 是編譯正則表達(dá)式的入口函數(shù),該函數(shù)返回編譯好的正則表達(dá)式對象和錯誤。
- 第 3 和第 4 行判斷如果有錯,則使用 panic() 觸發(fā)宕機(jī)。
- 第 6 行,沒有錯誤時返回正則表達(dá)式對象。
手動宕機(jī)進(jìn)行報錯的方式不是一種偷懶的方式,反而能迅速報錯,終止程序繼續(xù)運(yùn)行,防止更大的錯誤產(chǎn)生,不過,如果任何錯誤都使用宕機(jī)處理,也不是一種良好的設(shè)計習(xí)慣,因此應(yīng)根據(jù)需要來決定是否使用宕機(jī)進(jìn)行報錯。
在宕機(jī)時觸發(fā)延遲執(zhí)行語句
當(dāng) panic() 觸發(fā)的宕機(jī)發(fā)生時,panic() 后面的代碼將不會被運(yùn)行,但是在 panic() 函數(shù)前面已經(jīng)運(yùn)行過的 defer 語句依然會在宕機(jī)發(fā)生時發(fā)生作用,參考下面代碼:
package main
import "fmt"
func main() {
defer fmt.Println("宕機(jī)后要做的事情1")
defer fmt.Println("宕機(jī)后要做的事情2")
panic("宕機(jī)")
}代碼輸出如下:
宕機(jī)后要做的事情2
宕機(jī)后要做的事情1
panic: 宕機(jī)
goroutine 1 [running]:
main.main()
D:/code/main.go:8 +0xf8
exit status 2
對代碼的說明:
- 第 6 行和第 7 行使用 defer 語句延遲了 2 個語句。
- 第 8 行發(fā)生宕機(jī)。
宕機(jī)前,defer 語句會被優(yōu)先執(zhí)行,由于第 7 行的 defer 后執(zhí)行,因此會在宕機(jī)前,這個 defer 會優(yōu)先處理,隨后才是第 6 行的 defer 對應(yīng)的語句,這個特性可以用來在宕機(jī)發(fā)生前進(jìn)行宕機(jī)信息處理。
標(biāo)題名稱:創(chuàng)新互聯(lián)GO教程:Go語言宕機(jī)(panic)——程序終止運(yùn)行
網(wǎng)站地址:http://www.5511xx.com/article/dhscddp.html


咨詢
建站咨詢
