go waitgroup.done()异常处理_Go 异常处理
運(yùn)行時(shí)恐慌 panic
這種程序異常叫做 panic,我們把它翻譯成運(yùn)行時(shí)恐慌。其中恐慌是由 panic 直譯過(guò)來(lái)的,之所以加上運(yùn)行時(shí)是因?yàn)檫@種異常只會(huì)在程序運(yùn)行時(shí)的時(shí)候拋出來(lái)。
package mainimport "fmt"func main() { s := []int{0, 1, 2, 3, 4} fmt.Println(s[5])}//panic: runtime error: index out of range [5] with length 5////goroutine 1 [running]://main.main()///Users/zhangxuesong/gowork/src/gocore/gopanic/main.go:7 +0x1b//exit status 2上面這個(gè)切片只有 5 個(gè)元素,而用下標(biāo) 5 取第 6 個(gè)元素肯定不對(duì)的。Go 運(yùn)行時(shí)系統(tǒng)執(zhí)行到這一句時(shí)會(huì)拋出 panic,以提示我們索引越界了。如果我們沒(méi)有在程序里添加任何保護(hù)措施,程序打印出 panic 詳細(xì)信息后就會(huì)終止運(yùn)行。
詳情中 runtime error 表示這是一個(gè) runtime 包拋出的 panic。其中包含了一個(gè) runtime.Error 接口類型的值。runtime.Error 接口內(nèi)嵌了 error 接口,并做了一點(diǎn)點(diǎn)擴(kuò)展,runtime 包中有不少它的實(shí)現(xiàn)類型。
詳情中 panic: 右面的內(nèi)容正是這個(gè) panic 包含的 runtime.Error 類型值的字符串表示形式。
此外,panic 詳情中一般還會(huì)包含與它引發(fā)原因有關(guān)的 goroutine 的代碼執(zhí)行信息。正如詳情中的 goroutine 1 [running]:,它表示有一個(gè) ID 為 1 的 goroutine 在此 panic 被引發(fā)的時(shí)候正在運(yùn)行。這里的 ID 并不重要,它只是 Go 運(yùn)行時(shí)系統(tǒng)內(nèi)部給予的一個(gè)編號(hào),我們?cè)诔绦蛑惺菬o(wú)法獲取和更改的。
main.main() 表示這個(gè) goroutine 包裝的 go 函數(shù)就是命令源碼中的 main 函數(shù),也就是說(shuō)這里的 goroutine 正是主 goroutine。下面一行指出這個(gè) goroutine 中的哪一行代碼在此 panic 被引發(fā)時(shí)正在執(zhí)行。這包含了此行代碼所屬的源碼文件中的行數(shù)和文件所在的絕對(duì)路徑。最后的 +0x1b 代表此行代碼相對(duì)于其所屬函數(shù)的入口程序計(jì)數(shù)偏移量。一般情況下用處不大。
最后,exit status 2 表示這個(gè)程序是以退出狀態(tài)碼 2 結(jié)束運(yùn)行的。在大多數(shù)操作系統(tǒng)中,只要退出狀態(tài)碼不為 0,都意味著程序運(yùn)行的非正常結(jié)束。在 Go 語(yǔ)言中,因 panic 導(dǎo)致程序結(jié)束運(yùn)行的退出狀態(tài)碼一般都會(huì)是 2。
從 panic 被引發(fā)到程序終止的過(guò)程
某個(gè)函數(shù)中的某行代碼有意或無(wú)意的引發(fā)了一個(gè) panic。這時(shí),初始的 panic 詳情會(huì)被建立起來(lái),并且該程序的控制權(quán)會(huì)從此行代碼轉(zhuǎn)移至調(diào)用其所屬函數(shù)的那行代碼上,也就是調(diào)用棧的上一級(jí)。
這也意味著,此行代碼所屬的函數(shù)的執(zhí)行隨即終止。緊接著,控制權(quán)并不會(huì)在此有片刻停留,它又會(huì)立即轉(zhuǎn)移至再上一級(jí)的調(diào)用代碼處。控制權(quán)如此一級(jí)一級(jí)的沿著調(diào)用棧的反方向傳播至頂端,也就是我們編寫的最外層函數(shù)那里。
這里的最外層函數(shù)指的是 go 函數(shù),對(duì)于主 goroutine 來(lái)說(shuō)就是 main 函數(shù)。但是控制權(quán)也不會(huì)停留在那里,而是被 Go 運(yùn)行時(shí)系統(tǒng)回收。
隨后,程序崩潰并終止運(yùn)行,承載程序這次運(yùn)行的進(jìn)程也會(huì)隨之死亡和消失。與此同時(shí),在這個(gè)控制傳播過(guò)程中,panic 詳情會(huì)主鍵的積累和完善,并會(huì)在程序終止之前被打印出來(lái)。
panic 可能是我們?cè)跓o(wú)意間引發(fā)的,如前文所屬的索引越界。這類 panic 是真正的、在我們意料之外的程序異常。除此之外,我們還可以有意的引發(fā) panic。
Go 語(yǔ)言內(nèi)建函數(shù) panic 是專門用于引發(fā) panic 的。該函數(shù)使程序開發(fā)者可以在程序運(yùn)行期間報(bào)告異常。注意,這與函數(shù)返回錯(cuò)誤值的意義是完全不同的。當(dāng)我們的函數(shù)返回一個(gè)非 nil 的錯(cuò)誤值時(shí),函數(shù)的調(diào)用放有權(quán)選擇不處理,并且不處理的結(jié)果往往是不致命的。
這里的不致命是說(shuō)不至于使程序無(wú)法提供任何功能或者直接崩潰并終止運(yùn)行。
當(dāng)一個(gè) panic 發(fā)生時(shí),如果我們不加任何保護(hù)措施,那么導(dǎo)致的后果可能是程序崩潰,這顯然是致命的。
package mainimport ( "fmt")func main() { fmt.Println("Enter function main.") caller1() fmt.Println("Exit function main.")}func caller1() { fmt.Println("Enter function caller1.") caller2() fmt.Println("Exit function caller1.")}func caller2() { fmt.Println("Enter function caller2.") s1 := []int{0, 1, 2, 3, 4} e5 := s1[5] _ = e5 fmt.Println("Exit function caller2.")}提示:panic 詳情會(huì)在控制權(quán)傳播的過(guò)程中,被主鍵的積累和完善,并且,控制權(quán)會(huì)一級(jí)一級(jí)的沿著調(diào)用棧反方向傳播至頂端。
因此,在針對(duì)某個(gè) goroutine 的代碼執(zhí)行信息中,調(diào)用棧底層的信息會(huì)先出現(xiàn),然后是上一級(jí)的調(diào)用信息,以此類推,最后才是此調(diào)用棧頂端的信息。
Enter function main.Enter function caller1.Enter function caller2.panic: runtime error: index out of range [5] with length 5goroutine 1 [running]:main.caller2() /Users/zhangxuesong/gowork/src/gocore/gopanic/main1.go:22 +0x85main.caller1() /Users/zhangxuesong/gowork/src/gocore/gopanic/main1.go:15 +0x7emain.main() /Users/zhangxuesong/gowork/src/gocore/gopanic/main1.go:9 +0x7eexit status 2深入地了解此過(guò)程,以及正確地解讀 panic 詳情應(yīng)該是我們的必備技能,這在調(diào)試 Go 程序或者為 Go 程序排查錯(cuò)誤的時(shí)候非常重要。
總結(jié)
以上是生活随笔為你收集整理的go waitgroup.done()异常处理_Go 异常处理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: gb50268-2008给水排水管道施工
- 下一篇: java短横线转驼峰_Java后端常备的