亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何從等待組調用的函數中捕獲運行時錯誤?

如何從等待組調用的函數中捕獲運行時錯誤?

Go
繁花不似錦 2021-11-29 15:44:40
如何優雅地處理等待組中的崩潰?換句話說,在下面的代碼片段中,如何捕捉 goroutines 調用方法的恐慌/崩潰do()?func do(){    str := "abc"    fmt.Print(str[3])    defer func() {        if err := recover(); err != nil {            fmt.Print(err)        }    }()}func main() {    var wg sync.WaitGroup    for i := 0; i < 1; i++ {        wg.Add(1)        go do()        defer func() {            wg.Done()            if err := recover(); err != nil {                fmt.Print(err)            }        }()    }    wg.Wait()    fmt.Println("This line should be printed after all those invocations fail.")}
查看完整描述

2 回答

?
富國滬深

TA貢獻1790條經驗 獲得超9個贊

首先,注冊一個延遲函數來恢復應該是函數中的第一行,因為因為你是最后做的,它甚至不會被到達,因為defer已經發生恐慌之前的行/代碼所以延遲函數沒有被注冊哪個將恢復恐慌狀態。


因此,將您的do()功能更改為:


func do() {

    defer func() {

        if err := recover(); err != nil {

            fmt.Println("Restored:", err)

        }

    }()

    str := "abc"

    fmt.Print(str[3])

}

第二:僅此一項不會使您的代碼工作,因為您調用wg.Defer()了一個延遲函數,該函數只會在main()完成后運行- 這絕不是因為您調用wg.Wait()了main(). 所以wg.Wait()等待wg.Done()調用,但wg.Done()直到wg.Wait()返回才會運行調用。這是一個僵局。


您應該wg.Done()從do()函數調用,在延遲函數中,如下所示:


var wg sync.WaitGroup


func do() {

    defer func() {

        if err := recover(); err != nil {

            fmt.Println(err)

        }

        wg.Done()

    }()

    str := "abc"

    fmt.Print(str[3])

}


func main() {

    for i := 0; i < 1; i++ {

        wg.Add(1)

        go do()

    }

    wg.Wait()

    fmt.Println("This line should be printed after all those invocations fail.")

}

輸出(在Go Playground上試試):


Restored: runtime error: index out of range

This line should be printed after all those invocations fail.

這當然需要將wg變量移動到全局范圍。另一種選擇是將其do()作為參數傳遞給。如果您決定采用這種方式,請注意您必須將指針傳遞給WaitGroup,否則只會傳遞一個副本(WaitGroup是一種struct類型)并且調用WaitGroup.Done()副本不會對原始文件產生影響。


隨著傳遞WaitGroup到do():


func do(wg *sync.WaitGroup) {

    defer func() {

        if err := recover(); err != nil {

            fmt.Println("Restored:", err)

        }

        wg.Done()

    }()

    str := "abc"

    fmt.Print(str[3])

}


func main() {

    var wg sync.WaitGroup

    for i := 0; i < 1; i++ {

        wg.Add(1)

        go do(&wg)

    }

    wg.Wait()

    fmt.Println("This line should be printed after all those invocations fail.")

}

輸出是一樣的。在Go Playground上試試這個變體。


查看完整回答
反對 回復 2021-11-29
?
喵喵時光機

TA貢獻1846條經驗 獲得超7個贊

出色地解釋了如何正確使用WaitGroup及其功能Wait和Done


我喜歡WaitGroup簡單。但是,我不喜歡我們需要傳遞對 goroutine 的引用,因為這意味著并發邏輯將與您的業務邏輯混合。


所以我想出了這個通用函數來為我解決這個問題:


// Parallelize parallelizes the function calls

func Parallelize(functions ...func()) {

    var waitGroup sync.WaitGroup

    waitGroup.Add(len(functions))


    defer waitGroup.Wait()


    for _, function := range functions {

        go func(copy func()) {

            defer waitGroup.Done()

            copy()

        }(function)

    }

}

所以你的例子可以這樣解決:


func do() {

    defer func() {

        if err := recover(); err != nil {

            fmt.Println(err)

        }

    }()


    str := "abc"

    fmt.Print(str[3])

}


func main() {

    Parallelize(do, do, do)


    fmt.Println("This line should be printed after all those invocations fail.")

}

如果你想使用它,你可以在這里找到它https://github.com/shomali11/util


查看完整回答
反對 回復 2021-11-29
  • 2 回答
  • 0 關注
  • 186 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號