您好,登錄后才能下訂單哦!
這篇文章主要講解了“Golang異常處理之怎么優(yōu)雅地控制和處理異?!保闹械闹v解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Golang異常處理之怎么優(yōu)雅地控制和處理異?!卑?!
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中通過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() //開始調(diào)用f fmt.Println("f") //這里開始下面代碼不會(huì)再執(zhí)行 } func f(){ fmt.Println("a") panic("異常信息") fmt.Println("b") //這里開始下面代碼不會(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ì)直接崩潰
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
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í)行,但是程序崩潰了
如果 panic 和 recover 發(fā)生在同一個(gè)協(xié)程,那么 recover 是可以捕獲的,如果 panic 和 recover 發(fā)生在不同的協(xié)程,那么 recover 是不可以捕獲的
也就是哪個(gè)協(xié)程有panic,哪個(gè)協(xié)程里必須要有recover,否則會(huì)把整個(gè)程序弄崩潰
在使用 Golang 進(jìn)行開發(fā)時(shí),遇到 panic 是非常常見的情況。但是,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ì)象過多,可能會(huì)導(dǎo)致 panic 堆溢出,從而影響程序的性能
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ì)有問題。
感謝各位的閱讀,以上就是“Golang異常處理之怎么優(yōu)雅地控制和處理異?!钡膬?nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)Golang異常處理之怎么優(yōu)雅地控制和處理異常這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。