Golang新提案:panic?能不能加個(gè)?PanicError?
引言
在我們學(xué)習(xí)和平時(shí)使用 Go 時(shí),一定會(huì)涉及到一個(gè)內(nèi)置函數(shù) panic:
func panic(v any)
調(diào)用該函數(shù)后會(huì)停止代碼的控制流程并開始恐慌,達(dá)到扭轉(zhuǎn)當(dāng)前程序控制流的目的。在使用上也常常和 defer 和 recover 關(guān)聯(lián)上。
快速 Demo
以下是一個(gè)簡(jiǎn)單的使用 Demo:
func main() { panic("腦子進(jìn)煎魚了") _, err := os.Create("/tmp/file") if err != nil { log.Fatalln(err) } }
輸出結(jié)果:
$ go run demo.go
panic: 腦子進(jìn)煎魚了
goroutine 1 [running]:
main.main()
/Users/eddycjy/demo.go:10 +0x25
exit status 2
看著都沒什么問(wèn)題。輸出結(jié)果符合預(yù)期。
一點(diǎn)爭(zhēng)議
由于 Go 起協(xié)程(goroutine)非常簡(jiǎn)單、方便,因此絕大部分開發(fā)者在應(yīng)用程序中會(huì)經(jīng)常用 goroutine 去做各種并發(fā)處理的邏輯,一看不小心。就很有可能會(huì)引發(fā)程序中的 panic,導(dǎo)致整個(gè)應(yīng)該程序崩潰,出現(xiàn)事故。(見過(guò)好幾起低級(jí)錯(cuò)誤了,覺得程序沒問(wèn)題,所以也沒有主動(dòng)加防御性代碼)
有一個(gè)比較常見觸發(fā)的場(chǎng)景之一:空指針調(diào)用。時(shí)不時(shí)就能見到幾個(gè)應(yīng)用又誘發(fā)了。
如下代碼:
type T struct { Name string } func main() { var user *T go func() { // 異步執(zhí)行一些業(yè)務(wù)流程,不小心 panic 了... fmt.Println(user.Name) }() // 做一些事情... time.Sleep(time.Second * 1) fmt.Println("腦子進(jìn)煎魚了") }
輸出結(jié)果:
$ go run demo.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x1087178]goroutine 6 [running]:
main.main.func1()
/Users/eddycjy/demo.go:16 +0x18
created by main.main in goroutine 1
/Users/eddycjy/demo.go:14 +0x31
exit status 2
當(dāng)然,這也是有辦法解決的。標(biāo)準(zhǔn)的方式是通過(guò) recover,捕獲 panic。如下代碼:
go func() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }() // 異步執(zhí)行一些業(yè)務(wù)流程,不小心 panic 了... fmt.Println(user.Name) }()
輸出結(jié)果:
Recovered in f runtime error: invalid memory address or nil pointer dereference
腦子進(jìn)煎魚了
又或是基于 goroutine+recvoer 封裝一個(gè)協(xié)程調(diào)用的方法。要求使用這類工具庫(kù)來(lái)規(guī)避這個(gè) “坑”。
但不得不說(shuō),很多同學(xué)崩就崩在不覺得這個(gè)地方會(huì)出問(wèn)題,但就是有問(wèn)題。最后只能一溜煙全都用封裝好的工具庫(kù)來(lái)起 goroutine 了。
新提案:可定義 panic 錯(cuò)誤信息
在前面的案例中,我們可以看到 panic 后現(xiàn)在的輸出信息如下:
panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x1087178] goroutine 6 [running]: main.main.func1() /Users/eddycjy/demo.go:16 +0x18 created by main.main in goroutine 1 /Users/eddycjy/demo.go:14 +0x31 exit status 2
程序輸出了恐慌值和 goroutine 堆棧跟蹤。
這第一眼看起來(lái)是非常迷惑的,要看錯(cuò)誤信息。如果是程序內(nèi)拋的空指針,還要去翻堆棧信息去猜,再看是哪里的程序。做一輪排查、定位、驗(yàn)證。
因此社區(qū)里 @Mitar 提出了《proposal: runtime: provide a way to format output in unhandled panics[1]》的提案。希望可以針對(duì)意外情況+無(wú)人處理的 panic 錯(cuò)誤進(jìn)行自定義的格式化處理。
提案中希望 panic 新增 PanicError:
type panicError interface { error PanicError() string }
如果值實(shí)現(xiàn)了該接口,在 panic 時(shí)則會(huì)優(yōu)先調(diào)用 PanicError 方法,為錯(cuò)誤處理提供一個(gè)可選選項(xiàng),可以為調(diào)試補(bǔ)充額外的有用信息。
這樣就可以進(jìn)一步區(qū)分出 Panic 錯(cuò)誤和普通 Error 錯(cuò)誤的方法,并且針對(duì) Panic 的錯(cuò)誤做各種奇怪的操作和補(bǔ)充。
總結(jié)
今天給大家分享了社區(qū)對(duì)于 panic 優(yōu)化的一個(gè)小點(diǎn)。原提案作者的目的是為了針對(duì) panic 錯(cuò)誤新增 PanicError 方法,若存在則優(yōu)先使用該方法,而非與普通 error 共用 Error 方法,并以此去做好區(qū)分識(shí)別和實(shí)現(xiàn)。
在 Go 中對(duì) panic 的優(yōu)化,官方一直都是比較遲緩的。一方面是大佬們比較少寫業(yè)務(wù)代碼,另外一方面是類似對(duì) panic 加全局?jǐn)r截器避免崩潰等方式,也比較違背開創(chuàng)語(yǔ)言時(shí)的哲學(xué)宗旨。
參考資料
proposal: runtime: provide a way to format output in unhandled panics: https://github.com/golang/go/issues/63455
以上就是Golang新提案panic 能不能加個(gè) PanicError的問(wèn)題分析內(nèi)容,更多關(guān)于Go panic PanicError的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Goland調(diào)節(jié)字體大小的設(shè)置(編輯區(qū),terminal區(qū),頁(yè)面字體)
這篇文章主要介紹了Goland調(diào)節(jié)字體大小的設(shè)置(編輯區(qū),terminal區(qū),頁(yè)面字體),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12go goroutine 怎樣進(jìn)行錯(cuò)誤處理
在 Go 語(yǔ)言程序開發(fā)中,goroutine 的使用是比較頻繁的,因此在日常編碼的時(shí)候 goroutine 里的錯(cuò)誤處理,怎么做會(huì)比較好呢,本文就來(lái)詳細(xì)介紹一下2021-07-07Golang使用minio替代文件系統(tǒng)的實(shí)戰(zhàn)教程
本文討論項(xiàng)目開發(fā)中直接文件系統(tǒng)的限制或不足,接著介紹Minio對(duì)象存儲(chǔ)的優(yōu)勢(shì),同時(shí)給出Golang的實(shí)際示例代碼,包括初始化客戶端、讀取minio對(duì)象以及設(shè)置過(guò)期策略等,需要的朋友可以參考下2025-01-01go語(yǔ)言在請(qǐng)求http時(shí)加入自定義http header的方法
這篇文章主要介紹了go語(yǔ)言在請(qǐng)求http時(shí)加入自定義http header的方法,實(shí)例分析了Go語(yǔ)言http請(qǐng)求的原理與操作技巧,需要的朋友可以參考下2015-03-03詳解Go語(yǔ)言實(shí)現(xiàn)線性查找算法和二分查找算法
線性查找又稱順序查找,它是查找算法中最簡(jiǎn)單的一種。二分查找,也稱折半查找,相比于線性查找,它是一種效率較高的算法。本文將用Go語(yǔ)言實(shí)現(xiàn)這兩個(gè)查找算法,需要的可以了解一下2022-12-12