新聞中心
Recover 是一個Go語言的內(nèi)建函數(shù),可以讓進(jìn)入宕機(jī)流程中的 goroutine 恢復(fù)過來,recover 僅在延遲函數(shù) defer 中有效,在正常的執(zhí)行過程中,調(diào)用 recover 會返回 nil 并且沒有其他任何效果,如果當(dāng)前的 goroutine 陷入恐慌,調(diào)用 recover 可以捕獲到 panic 的輸入值,并且恢復(fù)正常的執(zhí)行。

晉中網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián),晉中網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為晉中成百上千提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請找那個售后服務(wù)好的晉中做網(wǎng)站的公司定做!
通常來說,不應(yīng)該對進(jìn)入 panic 宕機(jī)的程序做任何處理,但有時,需要我們可以從宕機(jī)中恢復(fù),至少我們可以在程序崩潰前,做一些操作,舉個例子,當(dāng) web 服務(wù)器遇到不可預(yù)料的嚴(yán)重問題時,在崩潰前應(yīng)該將所有的連接關(guān)閉,如果不做任何處理,會使得客戶端一直處于等待狀態(tài),如果 web 服務(wù)器還在開發(fā)階段,服務(wù)器甚至可以將異常信息反饋到客戶端,幫助調(diào)試。
提示
在其他語言里,宕機(jī)往往以異常的形式存在,底層拋出異常,上層邏輯通過 try/catch 機(jī)制捕獲異常,沒有被捕獲的嚴(yán)重異常會導(dǎo)致宕機(jī),捕獲的異??梢员缓雎?,讓代碼繼續(xù)運(yùn)行。
Go語言沒有異常系統(tǒng),其使用 panic 觸發(fā)宕機(jī)類似于其他語言的拋出異常,recover 的宕機(jī)恢復(fù)機(jī)制就對應(yīng)其他語言中的 try/catch 機(jī)制。
讓程序在崩潰時繼續(xù)執(zhí)行
下面的代碼實現(xiàn)了 ProtectRun() 函數(shù),該函數(shù)傳入一個匿名函數(shù)或閉包后的執(zhí)行函數(shù),當(dāng)傳入函數(shù)以任何形式發(fā)生 panic 崩潰后,可以將崩潰發(fā)生的錯誤打印出來,同時允許后面的代碼繼續(xù)運(yùn)行,不會造成整個進(jìn)程的崩潰。
保護(hù)運(yùn)行函數(shù):
package main
import (
"fmt"
"runtime"
)
// 崩潰時需要傳遞的上下文信息
type panicContext struct {
function string // 所在函數(shù)
}
// 保護(hù)方式允許一個函數(shù)
func ProtectRun(entry func()) {
// 延遲處理的函數(shù)
defer func() {
// 發(fā)生宕機(jī)時,獲取panic傳遞的上下文并打印
err := recover()
switch err.(type) {
case runtime.Error: // 運(yùn)行時錯誤
fmt.Println("runtime error:", err)
default: // 非運(yùn)行時錯誤
fmt.Println("error:", err)
}
}()
entry()
}
func main() {
fmt.Println("運(yùn)行前")
// 允許一段手動觸發(fā)的錯誤
ProtectRun(func() {
fmt.Println("手動宕機(jī)前")
// 使用panic傳遞上下文
panic(&panicContext{
"手動觸發(fā)panic",
})
fmt.Println("手動宕機(jī)后")
})
// 故意造成空指針訪問錯誤
ProtectRun(func() {
fmt.Println("賦值宕機(jī)前")
var a *int
*a = 1
fmt.Println("賦值宕機(jī)后")
})
fmt.Println("運(yùn)行后")
}
代碼輸出結(jié)果:
運(yùn)行前
手動宕機(jī)前
error: &{手動觸發(fā)panic}
賦值宕機(jī)前
runtime error: runtime error: invalid memory address or nil pointer dereference
運(yùn)行后
對代碼的說明:
- 第 9 行聲明描述錯誤的結(jié)構(gòu)體,保存執(zhí)行錯誤的函數(shù)。
- 第 17 行使用 defer 將閉包延遲執(zhí)行,當(dāng) panic 觸發(fā)崩潰時,ProtectRun() 函數(shù)將結(jié)束運(yùn)行,此時 defer 后的閉包將會發(fā)生調(diào)用。
- 第 20 行,recover() 獲取到 panic 傳入的參數(shù)。
- 第 22 行,使用 switch 對 err 變量進(jìn)行類型斷言。
- 第 23 行,如果錯誤是有 Runtime 層拋出的運(yùn)行時錯誤,如空指針訪問、除數(shù)為 0 等情況,打印運(yùn)行時錯誤。
- 第 25 行,其他錯誤,打印傳遞過來的錯誤數(shù)據(jù)。
- 第 44 行,使用 panic 手動觸發(fā)一個錯誤,并將一個結(jié)構(gòu)體附帶信息傳遞過去,此時,recover 就會獲取到這個結(jié)構(gòu)體信息,并打印出來。
- 第 57 行,模擬代碼中空指針賦值造成的錯誤,此時會由 Runtime 層拋出錯誤,被 ProtectRun() 函數(shù)的 recover() 函數(shù)捕獲到。
panic 和 recover 的關(guān)系
panic 和 recover 的組合有如下特性:
- 有 panic 沒 recover,程序宕機(jī)。
- 有 panic 也有 recover,程序不會宕機(jī),執(zhí)行完對應(yīng)的 defer 后,從宕機(jī)點退出當(dāng)前函數(shù)后繼續(xù)執(zhí)行。
提示
雖然 panic/recover 能模擬其他語言的異常機(jī)制,但并不建議在編寫普通函數(shù)時也經(jīng)常性使用這種特性。
在 panic 觸發(fā)的 defer 函數(shù)內(nèi),可以繼續(xù)調(diào)用 panic,進(jìn)一步將錯誤外拋,直到程序整體崩潰。
如果想在捕獲錯誤時設(shè)置當(dāng)前函數(shù)的返回值,可以對返回值使用命名返回值方式直接進(jìn)行設(shè)置。
本文標(biāo)題:創(chuàng)新互聯(lián)GO教程:Go語言宕機(jī)恢復(fù)(recover)——防止程序崩潰
網(wǎng)頁地址:http://fisionsoft.com.cn/article/dpcpggg.html


咨詢
建站咨詢
