<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 5879字,需瀏覽 12分鐘

           ·

          2023-08-31 22:49


          來(lái)源:旅途散記

          recover


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

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

           fmt.Println("222 Helloworld")
          }

          輸出為:

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

          對(duì)于goroutine中的panic,協(xié)程外面的recover是無(wú)法恢復(fù)的;goroutine中的recover,同樣無(wú)法恢復(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(),則同樣無(wú)法捕獲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ù)后面的語(yǔ)句都不會(huì)執(zhí)行了,所以recover函數(shù)不能放在panic語(yǔ)句后面執(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ù)中沒(méi)有捕獲異常信息,這個(gè)異常會(huì)沿著函數(shù)調(diào)用棧往上傳遞,直到 main 函數(shù)仍然沒(méi)有捕獲異常,將會(huì)導(dǎo)致程序異常退出


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

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

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

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



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


          不能!

          Go 有哪些無(wú)法恢復(fù)的致命場(chǎng)景?

          • 并發(fā)讀寫(xiě) 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!
          • 線程超過(guò)設(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 語(yǔ)言踩坑記——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 語(yǔ)言踩坑記——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)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美性爱内射在线 | 欧美日本操逼网站 | 欧美色图1| 日本理论片一道本 | 成人精品天堂一区二区三区五区 |