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

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

如何等待恐慌的協程?

如何等待恐慌的協程?

Go
富國滬深 2023-06-01 17:53:16
等待 goroutine 的常見方法是使用*sync.WaitGroup:func main() {    wg := &sync.WaitGroup{}    wg.Add(1)    go func() {        defer wg.Done()        // Long running task    }()    wg.Wait()}這里沒有問題。然而,這個呢:func main() {    wg := &sync.WaitGroup{}    wg.Add(1)    go func() {        defer wg.Done()        // Long running task        panic("Something unexpected happened.")    }()    wg.Wait()}在這種情況下,當wg.Done()被調用時,我相信main()可以在沒有panic()寫入stdout/的細節的情況下退出stderr。這是真的嗎?如果是,我該如何防止它發生?
查看完整描述

3 回答

?
LEATH

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

無論如何都會panic終止進程,因為沒有人從中恢復。如果你想在一個 goroutine 中從 panic 中恢復,你必須將recover調用堆棧包裝在同一個 goroutine 中。

wg.Done在這種情況下,將由defer聲明調用。但是這個過程可能會在主 goroutine 完成之前結束wg.Wait。


查看完整回答
反對 回復 2023-06-01
?
MMTTMM

TA貢獻1869條經驗 獲得超4個贊

參考src/builtin/builtin.go

panic 內置函數停止當前 goroutine 的正常執行。當函數 F 調用 panic 時,F 的正常執行會立即停止。任何被 F 延遲執行的函數都以通常的方式運行,然后 F 返回給它的調用者。對于調用者 G,調用 F 就像調用 panic,終止 G 的執行并運行任何延遲函數。這一直持續到執行 goroutine 中的所有函數都以相反的順序停止。此時,程序終止并報告錯誤情況,包括 panic 的參數值。這種終止序列稱為 panicing,可以通過內置函數 recover 來控制。

之后panic,defer將調用 func。

在操場上檢查一下:https ://play.golang.org/p/yrXkEbE1Af7

package main


import (

? ? "sync"

? ? "fmt"

)


func main() {

? ? wg := &sync.WaitGroup{}

? ? wg.Add(1)

? ? go func() {

? ? ? ? defer func(){

? ? ? ? ? ? fmt.Println("expected to be called after panic")

? ? ? ? ? ? wg.Done()

? ? ? ? }()

? ? ? ? // Long running task

? ? ? ? panic("Something unexpected happened.")

? ? }()

? ? wg.Wait()

}

輸出


expected to be called after panic

panic: Something unexpected happened.


goroutine 5 [running]:

main.main.func1(0x416020, 0x0)

? ? /tmp/sandbox946785562/main.go:17 +0x60

created by main.main

? ? /tmp/sandbox946785562/main.go:11 +0x80

那么你的第二個問題,“如何防止這種情況發生?”


如前所述,您可以recover在panic


游樂場:https://play.golang.org/p/76pPrCVYN8u


package main


import (

? ? "sync"

? ? "fmt"

)


func main() {

? ? wg := &sync.WaitGroup{}

? ? wg.Add(1)

? ? go func() {

? ? ? ? defer func(){

? ? ? ? ? ? if x:=recover();x!=nil{

? ? ? ? ? ? ? ? fmt.Printf("%+v\n",x)

? ? ? ? ? ? }

? ? ? ? ? ? wg.Done()

? ? ? ? }()

? ? ? ? // Long running task

? ? ? ? panic("Something unexpected happened.")

? ? }()

? ? wg.Wait()

? ? for i:=0;i<10;i++{

? ? ? ? fmt.Println(i)

? ? }

}

輸出


Something unexpected happened.

0

1

2

3

4

5

6

7

8

9


查看完整回答
反對 回復 2023-06-01
?
吃雞游戲

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

可以通過添加來引發不需要的行為defer time.Sleep(time.Second):


func main() {

? ? wg := &sync.WaitGroup{}

? ? wg.Add(1)

? ? go func() {

? ? ? ? defer time.Sleep(time.Second)

? ? ? ? defer wg.Done()

? ? ? ? // Long running task

? ? ? ? panic("Something unexpected happened.")

? ? }()

? ? wg.Wait()

}

D:\Projects\Code\Go\src\zyl\testexit>go build .

D:\Projects\Code\Go\src\zyl\testexit>.\testexit.exe

D:\Projects\Code\Go\src\zyl\testexit>echo %errorlevel%

0

該問題的解決方案是不延遲調用Done()并將其放在最后:


func main() {

? ? wg := &sync.WaitGroup{}

? ? wg.Add(1)

? ? go func() {

? ? ? ? // Long running task which might panic

? ? ? ? wg.Done()

? ? }()

? ? wg.Wait()

}

在上面的代碼中,不存在對 go routine 行為的實現細節的依賴,并且在發生 panic 時總是會失敗。


查看完整回答
反對 回復 2023-06-01
  • 3 回答
  • 0 關注
  • 172 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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