1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Go異常處理機(jī)制panic和recover

        共 5879字,需瀏覽 12分鐘

         ·

        2023-08-31 22:49


        來源:旅途散記

        recover


        使用panic拋出異常后, 將立即停止當(dāng)前函數(shù)的執(zhí)行并運(yùn)行所有被defer的函數(shù),然后將panic拋向上一層,直至程序crash。但是也可以使用被defer的recover函數(shù)來捕獲異常阻止程序的崩潰,recover只有被defer后才是有意義的。

        func main() {

         print(123)

         print(456)
         panic("throw an error")

         print(678//IDE會(huì)有提示: Unreachable code

        }

        結(jié)果:

        123456panic: throw an error

        goroutine 1 [running]:
        main.main()
            /Users/shuangcui/explore/panicandrecover.go:31 +0x67

        使用recover()捕獲異常:

        func main() {

         print(123)

         defer func() {
          if err := recover(); err != nil {
           print("recover it")
          }
         }()

         print(456)
         panic("throw an error")

         print(678//IDE會(huì)有提示: Unreachable code

        }

        結(jié)果為:

        123456recover it

        如果有兩個(gè)recover,則捕獲異常的是后一個(gè)

        func main() {

         print(123)

         defer func() {
          if err := recover(); err != nil {
           print("recover it")
          }
         }()

         defer func() {
          if err := recover(); err != nil {
           print("復(fù)原!")
          }
         }()

         print(456)
         panic("throw an error")

         print(678//IDE會(huì)有提示: Unreachable code

        }

        結(jié)果為:

        123456復(fù)原!

        panic之后的任何代碼都不會(huì)繼續(xù)執(zhí)行


        前提是panic不在if里面


        package main

        import "fmt"

        func main() {
         defer_call()
         fmt.Println("333 Helloworld")
        }

        func defer_call() {
         defer func() {
          fmt.Println("11111")
         }()

         defer func() {
          fmt.Println("22222")
         }()

         defer func() {
          if r := recover(); r != nil {
           fmt.Println("Recover from r : ", r)
          }
         }()

         defer func() {
          fmt.Println("33333")
         }()

         fmt.Println("111 Helloworld")

         panic("Panic 1!")


            //使用panic拋出異常后, 將立即停止當(dāng)前函數(shù)的執(zhí)行并運(yùn)行所有被defer的函數(shù),然后將panic拋向上一層, 直至程序crash

            //但是也可以使用被defer的recover函數(shù)來捕獲異常阻止程序的崩潰,recover只有被defer后才是有意義的。

         panic("Panic 2!"//panic1之后的panic2沒有任何機(jī)會(huì)會(huì)被執(zhí)行, panic2之后的任何代碼更沒有任何機(jī)會(huì)被執(zhí)行

         fmt.Println("222 Helloworld")
        }

        輸出為:

        111 Helloworld
        33333
        Recover from r :  Panic 1!
        22222
        11111
        333 Helloworld

        對(duì)于goroutine中的panic,協(xié)程外面的recover是無法恢復(fù)的;goroutine中的recover,同樣無法恢復(fù)協(xié)程外的panic



        但協(xié)程中的recover可以恢復(fù)協(xié)程中的panic

        package main

        import (
         "fmt"
         "time"
        )

        func main() {

         go func() {
          defer func() {
           if err := recover(); err != nil {
            fmt.Println("recover err:", err)
           }
          }()
          panic("里面出錯(cuò)了")
         }()

         //panic("外面出錯(cuò)了")

         time.Sleep(1 * time.Second)

        }

        輸出為:

        recover err 里面出錯(cuò)了


        主方法中的recover,也可以恢復(fù)子方法里的panic


        但如果go subfunc(),則同樣無法捕獲subfunc中的異常

        func main() {

         fmt.Println(123)

         defer fmt.Println(999)

         defer func() {
          if err := recover(); err != nil {
           fmt.Println("恢復(fù)異常:",err)
          }

         }()
         subfunc()

        }

        func subfunc() {

         defer fmt.Println(888)
         panic("出現(xiàn)了bug")

         defer fmt.Println(456)

        }

        結(jié)果為:

        123
        888
        恢復(fù)異常: 出現(xiàn)了bug
        999



        因?yàn)閜anic發(fā)生的時(shí)候,panic函數(shù)后面的語句都不會(huì)執(zhí)行了,所以recover函數(shù)不能放在panic語句后面執(zhí)行,而要放在defer函數(shù)中執(zhí)行。

        使用 panic 拋出異常后,函數(shù)執(zhí)行將從調(diào)用 panic 的地方停止,如果函數(shù)內(nèi)有 defer 調(diào)用,則執(zhí)行 defer 后邊的函數(shù)調(diào)用,如果 defer 調(diào)用的函數(shù)中沒有捕獲異常信息,這個(gè)異常會(huì)沿著函數(shù)調(diào)用棧往上傳遞,直到 main 函數(shù)仍然沒有捕獲異常,將會(huì)導(dǎo)致程序異常退出


        如何區(qū)別使用 panic 和 error 兩種方式?

        慣例是:導(dǎo)致關(guān)鍵流程出現(xiàn)不可修復(fù)性錯(cuò)誤的使用 panic ,其他使用 error 。

        panic 和 recover 的組合有如下特性:

        • 有 panic 沒 recover ,程序宕機(jī)。
        • 有 panic 也有 recover ,程序不會(huì)宕機(jī),執(zhí)行完對(duì)應(yīng)的 defer 后,從宕機(jī)點(diǎn)退出當(dāng)前函數(shù)后繼續(xù)執(zhí)行。



        recover能捕獲所有錯(cuò)誤嗎?


        不能!

        Go 有哪些無法恢復(fù)的致命場景?

        • 并發(fā)讀寫 map fatal error: concurrent map read and map write
        • 堆棧內(nèi)存耗盡(如遞歸)
        runtime: goroutine stack exceeds 1000000000-byte limit
        runtime: sp=0xc0200e1bf0 stack=[0xc0200e00000xc0400e0000]
        fatal error: stack overflow
        • 將 nil 函數(shù)作為 goroutine 啟動(dòng) fatal error: go of nil func value
        • goroutines 死鎖  fatal error: all goroutines are asleep - deadlock!
        • 線程超過設(shè)置的最大限制  fatal error: thread exhaustion
        • 超出可用內(nèi)存 fatal error: runtime: out of memory

        總之 都會(huì)報(bào)fatal error:xxxxxxxx


        拓展&參考:

        golang panic和recover 實(shí)現(xiàn)原理[1]

        Go 學(xué)習(xí)筆記(19)— 函數(shù)(05)[如何觸發(fā) panic、觸發(fā) panic 延遲執(zhí)行、panic 和 recover 的關(guān)系][2]

        Go 語言踩坑記——panic 與 recover[3]


        參考資料

        [1]

        golang panic和recover 實(shí)現(xiàn)原理: https://blog.csdn.net/u010853261/article/details/102761955

        [2]

        Go 學(xué)習(xí)筆記(19)— 函數(shù)(05)[如何觸發(fā) panic、觸發(fā) panic 延遲執(zhí)行、panic 和 recover 的關(guān)系]: https://blog.csdn.net/wohu1104/article/details/105571916

        [3]

        Go 語言踩坑記——panic 與 recover: https://xiaomi-info.github.io/2020/01/20/go-trample-panic-recover/



        想要了解Go更多內(nèi)容,歡迎掃描下方??關(guān)注公眾號(hào),回復(fù)關(guān)鍵詞 [實(shí)戰(zhàn)群]  ,就有機(jī)會(huì)進(jìn)群和我們進(jìn)行交流



        分享、在看與點(diǎn)贊Go 

        瀏覽 1567
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            久热欧美| 亚洲男同gay无套gaygay | 破外女一级视频免费出血 | 午夜国产偷拍 | 扒开你的腿做爽爽初视频 | 国产伦精品246区妓女 | 免费动漫吸乳羞羞网站视频 | 把老女人弄高潮七次 | 国产欧美黄片 | 黄色短视频网址在线播放 |