go waitgroup.done()异常处理_Go 异常处理
運行時恐慌 panic
這種程序異常叫做 panic,我們把它翻譯成運行時恐慌。其中恐慌是由 panic 直譯過來的,之所以加上運行時是因為這種異常只會在程序運行時的時候拋出來。
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上面這個切片只有 5 個元素,而用下標 5 取第 6 個元素肯定不對的。Go 運行時系統執行到這一句時會拋出 panic,以提示我們索引越界了。如果我們沒有在程序里添加任何保護措施,程序打印出 panic 詳細信息后就會終止運行。
詳情中 runtime error 表示這是一個 runtime 包拋出的 panic。其中包含了一個 runtime.Error 接口類型的值。runtime.Error 接口內嵌了 error 接口,并做了一點點擴展,runtime 包中有不少它的實現類型。
詳情中 panic: 右面的內容正是這個 panic 包含的 runtime.Error 類型值的字符串表示形式。
此外,panic 詳情中一般還會包含與它引發原因有關的 goroutine 的代碼執行信息。正如詳情中的 goroutine 1 [running]:,它表示有一個 ID 為 1 的 goroutine 在此 panic 被引發的時候正在運行。這里的 ID 并不重要,它只是 Go 運行時系統內部給予的一個編號,我們在程序中是無法獲取和更改的。
main.main() 表示這個 goroutine 包裝的 go 函數就是命令源碼中的 main 函數,也就是說這里的 goroutine 正是主 goroutine。下面一行指出這個 goroutine 中的哪一行代碼在此 panic 被引發時正在執行。這包含了此行代碼所屬的源碼文件中的行數和文件所在的絕對路徑。最后的 +0x1b 代表此行代碼相對于其所屬函數的入口程序計數偏移量。一般情況下用處不大。
最后,exit status 2 表示這個程序是以退出狀態碼 2 結束運行的。在大多數操作系統中,只要退出狀態碼不為 0,都意味著程序運行的非正常結束。在 Go 語言中,因 panic 導致程序結束運行的退出狀態碼一般都會是 2。
從 panic 被引發到程序終止的過程
某個函數中的某行代碼有意或無意的引發了一個 panic。這時,初始的 panic 詳情會被建立起來,并且該程序的控制權會從此行代碼轉移至調用其所屬函數的那行代碼上,也就是調用棧的上一級。
這也意味著,此行代碼所屬的函數的執行隨即終止。緊接著,控制權并不會在此有片刻停留,它又會立即轉移至再上一級的調用代碼處。控制權如此一級一級的沿著調用棧的反方向傳播至頂端,也就是我們編寫的最外層函數那里。
這里的最外層函數指的是 go 函數,對于主 goroutine 來說就是 main 函數。但是控制權也不會停留在那里,而是被 Go 運行時系統回收。
隨后,程序崩潰并終止運行,承載程序這次運行的進程也會隨之死亡和消失。與此同時,在這個控制傳播過程中,panic 詳情會主鍵的積累和完善,并會在程序終止之前被打印出來。
panic 可能是我們在無意間引發的,如前文所屬的索引越界。這類 panic 是真正的、在我們意料之外的程序異常。除此之外,我們還可以有意的引發 panic。
Go 語言內建函數 panic 是專門用于引發 panic 的。該函數使程序開發者可以在程序運行期間報告異常。注意,這與函數返回錯誤值的意義是完全不同的。當我們的函數返回一個非 nil 的錯誤值時,函數的調用放有權選擇不處理,并且不處理的結果往往是不致命的。
這里的不致命是說不至于使程序無法提供任何功能或者直接崩潰并終止運行。
當一個 panic 發生時,如果我們不加任何保護措施,那么導致的后果可能是程序崩潰,這顯然是致命的。
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 詳情會在控制權傳播的過程中,被主鍵的積累和完善,并且,控制權會一級一級的沿著調用棧反方向傳播至頂端。
因此,在針對某個 goroutine 的代碼執行信息中,調用棧底層的信息會先出現,然后是上一級的調用信息,以此類推,最后才是此調用棧頂端的信息。
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深入地了解此過程,以及正確地解讀 panic 詳情應該是我們的必備技能,這在調試 Go 程序或者為 Go 程序排查錯誤的時候非常重要。
總結
以上是生活随笔為你收集整理的go waitgroup.done()异常处理_Go 异常处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gb50268-2008给水排水管道施工
- 下一篇: java短横线转驼峰_Java后端常备的