Golang異常處理之優(yōu)雅地控制和處理異常
panic和recover使用
Go語(yǔ)言不支持傳統(tǒng)的 try…catch…finally 這種異常,因?yàn)镚o語(yǔ)言的設(shè)計(jì)者們認(rèn)為,將異常與控制結(jié)構(gòu)混在一起會(huì)很容易使得代碼變得混亂。在Go語(yǔ)言中,設(shè)計(jì)者們推薦使用多值返回來(lái)返回錯(cuò)誤。遇到真正的異常的情況下(比如除數(shù)為 0了)。才使用Go中引入的Exception處理:defer, panic, recover。
這幾個(gè)異常的使用場(chǎng)景可以這么簡(jiǎn)單描述:Go中可以拋出一個(gè)panic的異常,然后在defer中通過(guò)recover捕獲這個(gè)異常,然后正常處理
使用示例
package main
import "fmt"
func main(){
fmt.Println("c")
defer func(){ // 必須要先聲明defer,否則不能捕獲到panic異常
fmt.Println("d")
if err:=recover();err!=nil{
fmt.Println(err) // 這里的err其實(shí)就是panic傳入的內(nèi)容,55
}
fmt.Println("e")
}()
f() //開(kāi)始調(diào)用f
fmt.Println("f") //這里開(kāi)始下面代碼不會(huì)再執(zhí)行
}
func f(){
fmt.Println("a")
panic("異常信息")
fmt.Println("b") //這里開(kāi)始下面代碼不會(huì)再執(zhí)行
fmt.Println("f")
}
輸出結(jié)果:
c
a
d
異常信息
e
注意
- 利用recover處理panic指令,recover需要定義在defer匿名函數(shù)內(nèi)
- defer需要在panic之前聲明,否則當(dāng)panic時(shí),recover無(wú)法捕獲到panic
- panic無(wú)recover情況下,程序會(huì)直接崩潰
子函數(shù)panic主函數(shù)recover
func TestPanic(t *testing.T) {
defer func() {
if err := recover(); err != nil {
println("recovered")
}
}()
subFun()
subFun()
}
func subFun() {
println("subFun")
panic("subFun panic")
}
輸出結(jié)果如下,第一個(gè)sunFun后面的代碼不會(huì)執(zhí)行
subFun
recovered
子協(xié)程panic主函數(shù)recover
func subFun(i int) {
fmt.Println("subFun,i=", i)
panic("subFun panic")
}
func TestSubGoPanic(t *testing.T) {
defer func() {
if err := recover(); err != nil {
println("recovered2")
}
}()
go subFun(3)
subFun(4)
println("finish")
}
結(jié)果
subFun,i= 4
recovered2
subFun,i= 3
--- PASS: TestSubGoPanic (0.00s)
panic: subFun panic
goroutine 21 [running]:
zh.com/base/err.subFun(0x0?)
/Users/albert/file/code/go/zh/gotest/base/err/panic_test.go:34 +0x89
created by zh.com/base/err.TestSubGoPanic
/Users/albert/file/code/go/zh/gotest/base/err/panic_test.go:43 +0x46
recover會(huì)執(zhí)行,但是程序崩潰了
使用總結(jié)
如果 panic 和 recover 發(fā)生在同一個(gè)協(xié)程,那么 recover 是可以捕獲的,如果 panic 和 recover 發(fā)生在不同的協(xié)程,那么 recover 是不可以捕獲的
也就是哪個(gè)協(xié)程有panic,哪個(gè)協(xié)程里必須要有recover,否則會(huì)把整個(gè)程序弄崩潰
使用panic的幾點(diǎn)擔(dān)心
性能
在使用 Golang 進(jìn)行開(kāi)發(fā)時(shí),遇到 panic 是非常常見(jiàn)的情況。但是,panic 對(duì)于性能的影響是相對(duì)較小的,尤其是在實(shí)際使用中。
首先,Golang 在運(yùn)行時(shí)會(huì)維護(hù)一個(gè) panic 堆,用于存儲(chǔ)棧中的 panic 對(duì)象。當(dāng)程序遇到 panic 時(shí),會(huì)將該 panic 對(duì)象添加到 panic 堆中。panic 堆的大小是有限的,如果堆中的對(duì)象過(guò)多,可能會(huì)導(dǎo)致 panic 堆溢出,從而影響程序的性能
性能對(duì)比
func BenchmarkSubFunWithError(b *testing.B) {
for i := 0; i < b.N; i++ {
go subFunWithError(i)
}
}
func BenchmarkSubFunWithRecover(b *testing.B) {
for i := 0; i < b.N; i++ {
go subFunWithRecover(i)
}
}
func subFunWithRecover(i int) {
//fmt.Println("subFun,i=", i)
defer func() {
if error := recover(); error != nil {
//println("subFunWithRecover_recovered")
}
}()
time.Sleep(time.Second)
panic("subFun panic")
}
func subFunWithError(i int) error {
//fmt.Println("subFun,i=", i)
time.Sleep(time.Second)
return errors.New("subFunWithError")
}
BenchmarkSubFunWithError-12 673920 1992 ns/op 489 B/op 3 allocs/op
BenchmarkSubFunWithRecover-12 1000000 1229 ns/op 240 B/op 2 allocs/op反而使用panic的性能更好?
安全
另外一個(gè)比較擔(dān)心的點(diǎn)是panic容易導(dǎo)致崩潰,但是如上所示,只要main方法里做好recover,每個(gè)go協(xié)程使用封裝好的帶recover的方法來(lái)調(diào)用,其實(shí)并不會(huì)有問(wèn)題
到此這篇關(guān)于Golang異常處理之優(yōu)雅地控制和處理異常的文章就介紹到這了,更多相關(guān)Golang異常處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言中基本數(shù)據(jù)類(lèi)型的相互轉(zhuǎn)換詳解
Go在不同類(lèi)型的變量之間賦值時(shí)需要顯示轉(zhuǎn)換,不能自動(dòng)轉(zhuǎn)換。這篇文章主要和大家介紹了Go語(yǔ)言中基本數(shù)據(jù)類(lèi)型的相互轉(zhuǎn)換,感興趣的小伙伴可以了解一下2022-10-10
Go語(yǔ)言MySQLCURD數(shù)據(jù)庫(kù)操作示例詳解
這篇文章主要為大家介紹了Go語(yǔ)言MySQLCURD數(shù)據(jù)庫(kù)操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
GoLang RabbitMQ實(shí)現(xiàn)六種工作模式示例
這篇文章主要介紹了GoLang RabbitMQ實(shí)現(xiàn)六種工作模式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12
關(guān)于go-zero服務(wù)自動(dòng)收集問(wèn)題分析
這篇文章主要介紹了關(guān)于go-zero服務(wù)自動(dòng)收集問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12
淺談goland導(dǎo)入自定義包時(shí)出錯(cuò)(一招解決問(wèn)題)
這篇文章主要介紹了淺談goland導(dǎo)入自定義包時(shí)出錯(cuò)(一招解決問(wèn)題),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
Golang中fsnotify包監(jiān)聽(tīng)文件變化的原理詳解
Golang提供了一個(gè)強(qiáng)大的fsnotify包,它能夠幫助我們輕松實(shí)現(xiàn)文件系統(tǒng)的監(jiān)控,本文將深入探討fsnotify包的原理,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
Go實(shí)現(xiàn)字符串與數(shù)字的高效轉(zhuǎn)換
在軟件開(kāi)發(fā)的世界里,數(shù)據(jù)類(lèi)型轉(zhuǎn)換是一項(xiàng)基礎(chǔ)而重要的技能,尤其在Go語(yǔ)言這樣類(lèi)型嚴(yán)格的語(yǔ)言中,正確高效地進(jìn)行類(lèi)型轉(zhuǎn)換對(duì)于性能優(yōu)化和代碼質(zhì)量至關(guān)重要,本文給大家介紹了Go實(shí)現(xiàn)字符串與數(shù)字的高效轉(zhuǎn)換,需要的朋友可以參考下2024-02-02

