golang?recover函數(shù)使用中的一些坑解析
正文
眾所周知golang 中recover函數(shù)可以捕捉panic,防止在出現(xiàn)異常的情況下服務(wù)整個不可用。然而某些情況下recover也無法catch panic。下面就會說一些這些情況。
一,正常情況下
package?main import?"fmt" func?main(){ ????defer?func(){ ????????if?err?:=?recover();err?!=?nil{ ????????????fmt.Printf("err?=?%v",err) ????????} ????}() ????panic("a?panic") } 打印結(jié)果: err?=?a?panic Process?finished?with?exit?code?0
能正常catch panic
二, goroutine中panic
之前線上環(huán)境出現(xiàn)過接口出現(xiàn)panic導(dǎo)致服務(wù)不可用的情況,于是同事就直接在main函數(shù)加了個recover認(rèn)為萬事無憂了。實(shí)際上recover并不能捕捉到協(xié)程中的panic。
package?main import?"fmt" func?main(){ ????defer?func(){ ????????if?err?:=?recover();err?!=?nil{ ????????????fmt.Printf("err?=?%v",err) ????????} ????}() ????go?func(){ ????????panic("a?panic") ????}() ????select{} } 打印結(jié)果: panic:?a?panic goroutine?6?[running]: main.main.func2() ????I:/goProject/catchPanic.go:13?+0x40 created?by?main.main ????I:/goProject/catchPanic.go:12?+0x5e
實(shí)際上還是會panic導(dǎo)致服務(wù)不可用。
正確寫法
package?main import?"fmt" func?main(){ ????go?func(){ ????????defer?func(){ ????????????if?err?:=?recover();err?!=?nil{ ????????????????fmt.Printf("err?=?%v",err) ????????????} ????????}() ????????panic("a?panic") ????}() ????select?{} } 返回值: fatal?error:?all?goroutines?are?asleep?-?deadlock! goroutine?1?[select?(no?cases)]: main.main() ????I:/goProject/catchPanic.go:15?+0x41 err?=?a?panic Process?finished?with?exit?code?2
可以看到panic被正常捕捉,同時因?yàn)閟elect語句陷入阻塞,報了一個死鎖的錯。
三,間接調(diào)用recover
在我想要把recover封裝成成一個函數(shù)的時候,發(fā)現(xiàn)recover并沒有生效,因?yàn)閞ecover只有在被defer語句直接調(diào)用的時候才會生效。當(dāng)recover在其他函數(shù)內(nèi)部的時候無法正確捕捉到panic。
package?main import?"fmt" func?main(){ ????defer?cover() ????panic("a?panic") } func?cover(){ ????defer?func(){ ????????if?err?:=?recover();err!=?nil{ ????????????fmt.Println(err) ????????} ????}() } 返回值: panic:?a?panic goroutine?1?[running]: main.main() ????I:/goProject/catchPanic.go:7?+0x62
四,nil panic
panic要被捕捉,還需要滿足一種條件,就是panic不是nil panic,否則在進(jìn)行捕獲判斷的時候無法知道是panic沒有發(fā)生還是panic本身就是nil。
例如以下代碼
package?main import?"fmt" func?main()?{ ????defer?func(){ ????????if?err?:=?recover();err?!=?nil{ ????????????fmt.Println(err) ????????} ????????fmt.Println("after?recover") ????}() ????panic(nil) ????select{} } 返回值: after?recover
recover并沒有正確處理異常,因?yàn)楫惓5闹禐閚il。
五,總結(jié)
這篇文章講述了三種recover會失效的情況。
- 攜程中出現(xiàn)panic
- defer不直接調(diào)用recover
- panic的值為nil值
寫代碼的時候需要注意避免因?yàn)檫@幾種情況的出現(xiàn)而導(dǎo)致服務(wù)不可用。以上就是golang新手常遇見的一些坑。
以上就是golang recover函數(shù)使用中的一些坑解析的詳細(xì)內(nèi)容,更多關(guān)于golang recover函數(shù)坑的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09Golang使用Gin框架實(shí)現(xiàn)HTTP上傳文件過程介紹
由于需求中有文件上傳這一個需求,在這里我們就學(xué)習(xí)一下go語言如何上傳文件。本文主要通過表單的方式進(jìn)行文件上傳操作,本文實(shí)例為大家分享了Go實(shí)現(xiàn)文件上傳操作的具體代碼,供大家參考,具體內(nèi)容如下2023-04-04基于Go語言實(shí)現(xiàn)一個并發(fā)下載器
這篇文章主要為大家詳細(xì)介紹了如何利用GO語言實(shí)現(xiàn)一個并發(fā)的文件下載器,可以在不重新啟動整個下載的情況下處理錯誤,感興趣的小伙伴可以了解一下2023-10-10golang 實(shí)現(xiàn)Location跳轉(zhuǎn)方式
這篇文章主要介紹了golang 實(shí)現(xiàn)Location跳轉(zhuǎn)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-05-05淺析Go語言中的map數(shù)據(jù)結(jié)構(gòu)是如何實(shí)現(xiàn)的
在?Go?中,map?是一種用于存儲鍵值對的數(shù)據(jù)結(jié)構(gòu),它提供了一種快速查找和訪問數(shù)據(jù)的方式,下面我們就來看看Go語言中是如何實(shí)現(xiàn)map數(shù)據(jù)結(jié)構(gòu)的吧2024-03-03Goland 斷點(diǎn)調(diào)試Debug的操作
這篇文章主要介紹了Goland 斷點(diǎn)調(diào)試Debug的操作方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04使用golang實(shí)現(xiàn)一個MapReduce的示例代碼
這篇文章主要給大家介紹了關(guān)于如何使用golang實(shí)現(xiàn)一個MapReduce,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09