久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      記錄Golang Recover的一個(gè)小坑

      下面由golang教程欄目給大家介紹Golang Recover的一個(gè)小坑,希望對(duì)需要的朋友有所幫助!

      記錄Golang Recover的一個(gè)小坑

      1.error

      Golang被詬病非常多的一點(diǎn)就是缺少?gòu)?qiáng)大方便的異常處理機(jī)制,大部分高級(jí)編程語(yǔ)言,比如Java、PHP、Python等都擁有一種try catch機(jī)制,這種異常捕獲機(jī)制可以非常方便的處理程序運(yùn)行中可能出現(xiàn)的各種意外情況。

      嚴(yán)格來(lái)說(shuō),在Go里面,錯(cuò)誤和異常是2種不同的類型,錯(cuò)誤一般是指程序產(chǎn)生的邏輯錯(cuò)誤,或者意料之中的意外情況,而且異常一般就是panic,比如角標(biāo)越界、段錯(cuò)誤。

      對(duì)于錯(cuò)誤,Golang采用了一種非常原始的手段,我們必須手動(dòng)處理可能產(chǎn)生的每一個(gè)錯(cuò)誤,一般會(huì)把錯(cuò)誤返回給調(diào)用方,下面這種寫(xiě)法在Go里面十分常見(jiàn):

      package mainimport (     "errors"     "fmt")func main() {     s, err := say()     if err != nil {         fmt.Printf("%sn", err.Error())     } else {         fmt.Printf("%sn", s)     }}func say() (string, error) {     // do something     return "", errors.New("something error")}復(fù)制代碼

      這種寫(xiě)法最大的問(wèn)題就是每一個(gè)error都需要判斷處理,非常繁瑣,如果使用try catch機(jī)制,我們就可以統(tǒng)一針對(duì)多個(gè)函數(shù)調(diào)用可能產(chǎn)生的錯(cuò)誤做處理,節(jié)省一點(diǎn)代碼和時(shí)間。不過(guò)咱們今天不是來(lái)討論Go的異常錯(cuò)誤處理機(jī)制的,這里只是簡(jiǎn)單說(shuō)一下。

      2.panic

      一般錯(cuò)誤都是顯示的,程序明確返回的,而異常往往是隱示的,不可預(yù)測(cè)的,比如下面的代碼:

      package mainimport "fmt"func main() {     fmt.Printf("%dn", cal(1,2))     fmt.Printf("%dn", cal(5,2))     fmt.Printf("%dn", cal(5,0)) //panic: runtime error: integer pide by zero      fmt.Printf("%dn", cal(9,5))}func cal(a, b int) int {     return a / b}復(fù)制代碼

      在執(zhí)行第三個(gè)計(jì)算的時(shí)候會(huì)發(fā)生一個(gè)panic,這種錯(cuò)誤會(huì)導(dǎo)致程序退出,下面的代碼的就無(wú)法執(zhí)行了。當(dāng)然你可以說(shuō)這種錯(cuò)誤理論上是可以預(yù)測(cè)的,我們只要在cal函數(shù)內(nèi)部做好處理就行了。

      然而實(shí)際開(kāi)發(fā)中,會(huì)發(fā)生panic的地方可能特別多,而且不是這種一眼就能看出來(lái)的,在Web服務(wù)中,這樣的panic會(huì)導(dǎo)致整個(gè)Web服務(wù)掛掉,特別危險(xiǎn)。

      3.recover

      雖然沒(méi)有try catch機(jī)制,Go其實(shí)有一種類似的recover機(jī)制,功能弱了點(diǎn),用法很簡(jiǎn)單:

      package mainimport "fmt"func main() {     fmt.Printf("%dn", cal(1, 2))     fmt.Printf("%dn", cal(5, 2))     fmt.Printf("%dn", cal(5, 0))     fmt.Printf("%dn", cal(9, 2))}func cal(a, b int) int {     defer func() {         if err := recover(); err != nil {             fmt.Printf("%sn", err)         }     }()     return a / b}復(fù)制代碼

      首先,大家得理解defer的作用,簡(jiǎn)單說(shuō)defer就類似于面向?qū)ο罄锩娴奈鰳?gòu)函數(shù),在這個(gè)函數(shù)終止的時(shí)候會(huì)執(zhí)行,即使是panic導(dǎo)致的終止。

      所以,在cal函數(shù)里面每次終止的時(shí)候都會(huì)檢查有沒(méi)有異常產(chǎn)生,如果產(chǎn)生了我們可以處理,比如說(shuō)記錄日志,這樣程序還可以繼續(xù)執(zhí)行下去。

      4.注意的坑

      一般defer recover這種機(jī)制經(jīng)常用在常駐進(jìn)程的應(yīng)用,比如Web服務(wù),在Go里面,每一個(gè)Web請(qǐng)求都會(huì)分配一個(gè)goroutine去處理,在沒(méi)有做任何處理的情況下,假如某一個(gè)請(qǐng)求發(fā)生了panic,就會(huì)導(dǎo)致整個(gè)服務(wù)掛掉,這是不可接受的,所以在Web應(yīng)用里面必須使用recover保證即使某一個(gè)請(qǐng)求發(fā)生錯(cuò)誤也不影響其它請(qǐng)求。

      這里我使用一小段代碼模擬一下:

      package mainimport (     "fmt")func main() {     requests := []int{12, 2, 3, 41, 5, 6, 1, 12, 3, 4, 2, 31}     for n := range requests {         go run(n) //開(kāi)啟多個(gè)協(xié)程     }      for {         select {}     }}func run(num int) {     //模擬請(qǐng)求錯(cuò)誤     if num%5 == 0 {         panic("請(qǐng)求出錯(cuò)")     }     fmt.Printf("%dn", num)}復(fù)制代碼

      上面這段代碼無(wú)法完整執(zhí)行下去,因?yàn)槠渲心骋粋€(gè)協(xié)程必然會(huì)發(fā)生panic,從而導(dǎo)致整個(gè)應(yīng)用掛掉,其它協(xié)程也停止執(zhí)行。

      解決方法和上面一樣,我們只需要在run函數(shù)里面加入defer recover,整個(gè)程序就會(huì)非常健壯,即使發(fā)生panic,也會(huì)完整的執(zhí)行下去。

      func run(num int) {     defer func() {         if err := recover();err != nil {             fmt.Printf("%sn", err)         }     }()     if num%5 == 0 {         panic("請(qǐng)求出錯(cuò)")     }     fmt.Printf("%dn", num)}復(fù)制代碼

      上面的代碼只是演示,真正的坑是:如果你在run函數(shù)里面又啟動(dòng)了其它協(xié)程,這個(gè)協(xié)程發(fā)生的panic是無(wú)法被recover的,還是會(huì)導(dǎo)致整個(gè)進(jìn)程掛掉,我們改造了一下上面的例子:

      func run(num int) {     defer func() {         if err := recover(); err != nil {             fmt.Printf("%sn", err)         }     }()     if num%5 == 0 {         panic("請(qǐng)求出錯(cuò)")     }     go myPrint(num)}func myPrint(num int) {     if num%4 == 0 {         panic("請(qǐng)求又出錯(cuò)了")     }     fmt.Printf("%dn", num)}復(fù)制代碼

      我在run函數(shù)里面又通過(guò)協(xié)程的方式調(diào)用了另一個(gè)函數(shù),而這個(gè)函數(shù)也會(huì)發(fā)生panic,你會(huì)發(fā)現(xiàn)整個(gè)程序也掛了,即使run函數(shù)有recover也沒(méi)有任何作用,這意味著我們還需要在myPrint函數(shù)里面加入recover。但是如果你不使用協(xié)程的方式調(diào)用myPrint函數(shù),直接調(diào)用的話還是可以捕獲recover的。

      總結(jié)一下就是defer recover這種機(jī)制只是針對(duì)當(dāng)前函數(shù)和以及直接調(diào)用的函數(shù)可能產(chǎn)生的panic,它無(wú)法處理其調(diào)用產(chǎn)生的其它協(xié)程的panic,這一點(diǎn)和try catch機(jī)制不一樣。

      理論上講,所有使用協(xié)程的地方都必須做defer recover處理,這樣才能保證你的應(yīng)用萬(wàn)無(wú)一失,不過(guò)開(kāi)發(fā)中可以根據(jù)實(shí)際情況而定,對(duì)于一些不可能出錯(cuò)的函數(shù)加了還影響性能。

      Go的Web服務(wù)也是一樣,默認(rèn)的recover機(jī)制只能捕獲一層,如果你在這個(gè)請(qǐng)求的處理中又使用了其它協(xié)程,那么必須非常慎重,畢竟只要發(fā)生一個(gè)panic,整個(gè)Web服務(wù)就會(huì)掛掉。

      最后,總結(jié)一下,Go的異常處理機(jī)制雖然沒(méi)有很多其它語(yǔ)言高效,但是基本上還是能滿足需求,目前官方已經(jīng)在著完善這一點(diǎn),Go2可能會(huì)見(jiàn)到。

      推薦:《go語(yǔ)言教程

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)