為什麼我只收到部分錯誤,而不是我啟動的 goroutine 中的所有錯誤?
php小編蘋果為你解答:在Go語言中,當一個goroutine發生錯誤時,並不會自動傳播給主協程。相反,它會被靜默地忽略掉,這可能會導致你只收到部分錯誤而不是啟動的所有goroutine中的錯誤。這是因為Go語言設計的初衷是讓程式保持穩定和高效,即使在出現錯誤的情況下也不會立即停止整個程式。如果你想要捕捉所有的錯誤,你可以使用通道或其他機制來顯示地傳遞錯誤訊息。這樣你就可以確保所有的錯誤都被正確處理。
問題內容
我定義了一個cycle類別來處理並發任務。我想要的是運行兩個函數,每個函數都在一個 goroutine 中,等待它們完成並將它們的輸出錯誤合併在一起。但我只收到一個錯誤。每個方法的職責如下:
run
-在goroutine中運行函數,並收集其錯誤
waitalldone
-將所有函數錯誤合併在一起並等待所有函數完成
do1、do2
- 測試函數
import ( "fmt" "go.uber.org/multierr" "sync" "testing" ) type Cycle struct { errChan chan error wg sync.WaitGroup } func NewCycle() *Cycle { return &Cycle{ errChan: make(chan error), wg: sync.WaitGroup{}, } } // run fn and collect its error into error channel func (c *Cycle) Run(fn func() error) { c.wg.Add(1) go func() { defer c.wg.Done() if err := fn(); err != nil { c.errChan <- err } }() } // wait all fn finish and combine their error together func (c *Cycle) WaitAllDone() error { var err error go func() { for { if tmpErr, ok := <-c.errChan; ok { err = multierr.Append(err, tmpErr) } else{ break } } }() c.wg.Wait() close(c.errChan) return err } func Do1() error { return fmt.Errorf("ERR1") } func Do2() error { return fmt.Errorf("ERR2") } func Test41(t *testing.T) { c := NewCycle() c.Run(Do1) c.Run(Do2) if err := c.WaitAllDone(); err != nil { t.Log(err) } }
最終t.log(err)
輸出err1
或err2
,但我希望它輸出err1 err2
。為什麼它會漏掉一個錯誤。
解決方法
這是因為 (*cycle).waitalldone
不會等待收集錯誤的 goroutine 完成。如果您使用 -race
標誌來執行程式碼,有時它可能會報告幾個 data race 錯誤。這是其中之一:
$ go test -race . ================== warning: data race write at 0x00c0000a0610 by goroutine 10: m.(*cycle).waitalldone.func1() /home/zeke/src/temp/76370962/main_test.go:40 +0xb6 previous read at 0x00c0000a0610 by goroutine 7: m.(*cycle).waitalldone() /home/zeke/src/temp/76370962/main_test.go:48 +0x14e m.test41() /home/zeke/src/temp/76370962/main_test.go:63 +0xa4 testing.trunner() /snap/go/current/src/testing/testing.go:1576 +0x216 testing.(*t).run.func1() /snap/go/current/src/testing/testing.go:1629 +0x47
此變更將解決該問題:
func (c *cycle) waitalldone() error { var err error + done := make(chan int) go func() { for { if tmperr, ok := <-c.errchan; ok { err = multierr.append(err, tmperr) } else { break } } + close(done) }() c.wg.wait() close(c.errchan) + <-done return err }
並且可以使用 range
子句來簡化 for 迴圈:
func (c *Cycle) WaitAllDone() error { var err error done := make(chan int) go func() { for tmpErr := range c.errChan { err = multierr.Append(err, tmpErr) } close(done) }() c.wg.Wait() close(c.errChan) <-done return err }
以上是為什麼我只收到部分錯誤,而不是我啟動的 goroutine 中的所有錯誤?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Go語言中使用RedisStream實現消息隊列時類型轉換問題在使用Go語言與Redis...

GoLand中自定義結構體標籤不顯示怎麼辦?在使用GoLand進行Go語言開發時,很多開發者會遇到自定義結構體標籤在�...

Go爬蟲Colly中的Queue線程問題探討在使用Go語言的Colly爬蟲庫時,開發者常常會遇到關於線程和請求隊列的問題。 �...

Go語言中用於浮點數運算的庫介紹在Go語言(也稱為Golang)中,進行浮點數的加減乘除運算時,如何確保精度是�...

Go語言中字符串打印的區別:使用Println與string()函數的效果差異在Go...

Go語言中結構體定義的兩種方式:var與type關鍵字的差異Go語言在定義結構體時,經常會看到兩種不同的寫法:一�...

Go語言中哪些庫是大公司開發或知名開源項目?在使用Go語言進行編程時,開發者常常會遇到一些常見的需求,�...
