panic 捕獲及 throw 崩潰

一,go 語言 panic 報錯捕獲 安全

    使用 go 語言的同窗在真實項目中應該常常出現空指針使用等 panic 報錯,這類報錯與 C++ 中的 try-catch 模塊不一樣,go 語言會一直將當前 panic 一直從報錯棧傳至最外層的棧,因此不少 go 語言的架構都會在架構中 handler 的入口添加一串代碼多線程

1     defer func() {
2         if x := recover(); x != nil {
3             // TODO fix panic
4         }
5     }()

     這裏講幾個關鍵字架構

     defer:註冊一個回調函數,在當前棧退出時,按註冊入棧的順序,從最後註冊的 defer 函數開始執行,函數內部發生 panic,屬於可修復型崩潰,因此 go 語言會有序的退出棧,並執行 defer 函數併發

     recover:捕捉 panic 異常,並打斷當前的 panic,進行處理修復,保證不會讓單個 handler 影響到整個程序函數

     上述的異常捕獲方法想必熟悉 go 語言的同窗基本都能瞭解。但下面咱們瞭解一些 go 語言中沒法崩潰和修復的 throw 崩潰工具

 二,go 語言 throw 奔潰 post

      其實 go 語言源碼中一些地方有一些 throw 調用,這個函數會打印相應的 fatal msg,並退出整個程序,由於這類報錯被 go 語言認爲沒法動態修復的崩潰。因此這類奔潰與 panic 不一樣,屬於沒法經過 defer 和 recover 捕獲的崩潰(由於沒法修復),簡單舉兩個栗子atom

      lock:當使用一個初始化的鎖,並未加鎖就在代碼中就解鎖,就會發生 throw 崩潰spa

1 var lock sync.Mutex
2 lock.Unlock()  // fatal: sync: unlock of unlocked mutex
3 
4 
5 // from go 1.91
6 new := atomic.AddInt32(&m.state, -mutexLocked)
7 if (new+mutexLocked)&mutexLocked == 0 {
8     throw("sync: unlock of unlocked mutex") // post a throw
9 }

 

      map:熟悉 go 語言的開發者都知道,在 go 多攜程架構使用便利的狀況下,每每存在不少線程不安全的變量,map 就是其中最經典的栗子,當在併發下,在沒有添加讀寫鎖的狀況下對 map 進行寫、讀寫操做時,也會拋出 throw 崩潰線程

testmap := make([int],1)
for i := 0; i < 1000; i++ {
    go func() {
                for true{
                    testmap[1] = 10 // fatal: sync: curcurent map writes
                }    
    }()
}

 

      須要注意的是,這類崩潰是直接 down 掉整個進程的,因此咱們線上使用 go 語言進行應用開發時,必定要記得使用 supervisor 之類的進程管理工具,確保進行崩潰後先拉起來,再進行修復。不然會產生大面積機器徹底宕機的狀況。

      再須要注意的一點是,go 語言中一個進程每每有不少 goroutinue 在同時進行,若是發生 throw 奔潰時,整個進程都會被關掉,若是經過日誌,會發現打印了無數堆棧信息的日誌(全部 goroutinue 的日誌),這時候千萬不要在堆棧日誌上下功夫了,由於打印出來的都是正常日誌,只須要查看日誌中的 fatal 關鍵字便可找出真正的問題所在。

相關文章
相關標籤/搜索