GolangRecover中有哪些坑需要注意

這篇文章主要介紹了Golang Recover中有哪些坑需要注意,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),天等企業(yè)網(wǎng)站建設(shè),天等品牌網(wǎng)站建設(shè),網(wǎng)站定制,天等網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,天等網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。

1.error

Golang被詬病非常多的一點就是缺少強大方便的異常處理機制,大部分高級編程語言,比如Java、PHP、Python等都擁有一種try catch機制,這種異常捕獲機制可以非常方便的處理程序運行中可能出現(xiàn)的各種意外情況。

嚴格來說,在Go里面,錯誤和異常是2種不同的類型,錯誤一般是指程序產(chǎn)生的邏輯錯誤,或者意料之中的意外情況,而且異常一般就是panic,比如角標越界、段錯誤。

對于錯誤,Golang采用了一種非常原始的手段,我們必須手動處理可能產(chǎn)生的每一個錯誤,一般會把錯誤返回給調(diào)用方,下面這種寫法在Go里面十分常見:

package mainimport (
    "errors"
    "fmt")func main() {
    s, err := say()
    if err != nil {
        fmt.Printf("%s\n", err.Error())
    } else {
        fmt.Printf("%s\n", s)
    }}func say() (string, error) {
    // do something
    return "", errors.New("something error")}復(fù)制代碼

這種寫法最大的問題就是每一個error都需要判斷處理,非常繁瑣,如果使用try catch機制,我們就可以統(tǒng)一針對多個函數(shù)調(diào)用可能產(chǎn)生的錯誤做處理,節(jié)省一點代碼和時間。不過咱們今天不是來討論Go的異常錯誤處理機制的,這里只是簡單說一下。

2.panic

一般錯誤都是顯示的,程序明確返回的,而異常往往是隱示的,不可預(yù)測的,比如下面的代碼:

package mainimport "fmt"func main() {
    fmt.Printf("%d\n", cal(1,2))
    fmt.Printf("%d\n", cal(5,2))
    fmt.Printf("%d\n", cal(5,0)) //panic: runtime error: integer pide by zero 
    fmt.Printf("%d\n", cal(9,5))}func cal(a, b int) int {
    return a / b}復(fù)制代碼

在執(zhí)行第三個計算的時候會發(fā)生一個panic,這種錯誤會導(dǎo)致程序退出,下面的代碼的就無法執(zhí)行了。當然你可以說這種錯誤理論上是可以預(yù)測的,我們只要在cal函數(shù)內(nèi)部做好處理就行了。

然而實際開發(fā)中,會發(fā)生panic的地方可能特別多,而且不是這種一眼就能看出來的,在Web服務(wù)中,這樣的panic會導(dǎo)致整個Web服務(wù)掛掉,特別危險。

3.recover

雖然沒有try catch機制,Go其實有一種類似的recover機制,功能弱了點,用法很簡單:

package mainimport "fmt"func main() {
    fmt.Printf("%d\n", cal(1, 2))
    fmt.Printf("%d\n", cal(5, 2))
    fmt.Printf("%d\n", cal(5, 0))
    fmt.Printf("%d\n", cal(9, 2))}func cal(a, b int) int {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("%s\n", err)
        }
    }()
    return a / b}復(fù)制代碼

首先,大家得理解defer的作用,簡單說defer就類似于面向?qū)ο罄锩娴奈鰳?gòu)函數(shù),在這個函數(shù)終止的時候會執(zhí)行,即使是panic導(dǎo)致的終止。

所以,在cal函數(shù)里面每次終止的時候都會檢查有沒有異常產(chǎn)生,如果產(chǎn)生了我們可以處理,比如說記錄日志,這樣程序還可以繼續(xù)執(zhí)行下去。

4.注意的坑

一般defer recover這種機制經(jīng)常用在常駐進程的應(yīng)用,比如Web服務(wù),在Go里面,每一個Web請求都會分配一個goroutine去處理,在沒有做任何處理的情況下,假如某一個請求發(fā)生了panic,就會導(dǎo)致整個服務(wù)掛掉,這是不可接受的,所以在Web應(yīng)用里面必須使用recover保證即使某一個請求發(fā)生錯誤也不影響其它請求。

這里我使用一小段代碼模擬一下:

package mainimport (
    "fmt")func main() {
    requests := []int{12, 2, 3, 41, 5, 6, 1, 12, 3, 4, 2, 31}
    for n := range requests {
        go run(n) //開啟多個協(xié)程
    }

    for {
        select {}
    }}func run(num int) {
    //模擬請求錯誤
    if num%5 == 0 {
        panic("請求出錯")
    }
    fmt.Printf("%d\n", num)}復(fù)制代碼

上面這段代碼無法完整執(zhí)行下去,因為其中某一個協(xié)程必然會發(fā)生panic,從而導(dǎo)致整個應(yīng)用掛掉,其它協(xié)程也停止執(zhí)行。

解決方法和上面一樣,我們只需要在run函數(shù)里面加入defer recover,整個程序就會非常健壯,即使發(fā)生panic,也會完整的執(zhí)行下去。

func run(num int) {
    defer func() {
        if err := recover();err != nil {
            fmt.Printf("%s\n", err)
        }
    }()
    if num%5 == 0 {
        panic("請求出錯")
    }
    fmt.Printf("%d\n", num)}復(fù)制代碼

上面的代碼只是演示,真正的坑是:如果你在run函數(shù)里面又啟動了其它協(xié)程,這個協(xié)程發(fā)生的panic是無法被recover的,還是會導(dǎo)致整個進程掛掉,我們改造了一下上面的例子:

func run(num int) {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("%s\n", err)
        }
    }()
    if num%5 == 0 {
        panic("請求出錯")
    }
    go myPrint(num)}func myPrint(num int) {
    if num%4 == 0 {
        panic("請求又出錯了")
    }
    fmt.Printf("%d\n", num)}復(fù)制代碼

我在run函數(shù)里面又通過協(xié)程的方式調(diào)用了另一個函數(shù),而這個函數(shù)也會發(fā)生panic,你會發(fā)現(xiàn)整個程序也掛了,即使run函數(shù)有recover也沒有任何作用,這意味著我們還需要在myPrint函數(shù)里面加入recover。但是如果你不使用協(xié)程的方式調(diào)用myPrint函數(shù),直接調(diào)用的話還是可以捕獲recover的。

總結(jié)一下就是defer recover這種機制只是針對當前函數(shù)和以及直接調(diào)用的函數(shù)可能產(chǎn)生的panic,它無法處理其調(diào)用產(chǎn)生的其它協(xié)程的panic,這一點和try catch機制不一樣。

理論上講,所有使用協(xié)程的地方都必須做defer recover處理,這樣才能保證你的應(yīng)用萬無一失,不過開發(fā)中可以根據(jù)實際情況而定,對于一些不可能出錯的函數(shù)加了還影響性能。

Go的Web服務(wù)也是一樣,默認的recover機制只能捕獲一層,如果你在這個請求的處理中又使用了其它協(xié)程,那么必須非常慎重,畢竟只要發(fā)生一個panic,整個Web服務(wù)就會掛掉。

感謝你能夠認真閱讀完這篇文章,希望小編分享Golang Recover中有哪些坑需要注意內(nèi)容對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,遇到問題就找創(chuàng)新互聯(lián),詳細的解決方法等著你來學習!

網(wǎng)頁名稱:GolangRecover中有哪些坑需要注意
轉(zhuǎn)載注明:http://bm7419.com/article8/pccdop.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、軟件開發(fā)、App開發(fā)外貿(mào)網(wǎng)站建設(shè)、ChatGPT、外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)