在下面的代碼塊中,我嘗試運行幾個例程并為所有例程獲取結果(無論是成功還是錯誤)。
package main
import (
"fmt"
"sync"
)
func processBatch(num int, errChan chan<- error, resultChan chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
if num == 3 {
resultChan <- 0
errChan <- fmt.Errorf("goroutine %d's error returned", num)
} else {
square := num * num
resultChan <- square
errChan <- nil
}
}
func main() {
var wg sync.WaitGroup
batches := [5]int{1, 2, 3, 4, 5}
resultChan := make(chan int)
errChan := make(chan error)
for i := range batches {
wg.Add(1)
go processBatch(batches[i], errChan, resultChan, &wg)
}
var results [5]int
var err [5]error
for i := range batches {
results[i] = <-resultChan
err[i] = <-errChan
}
wg.Wait()
close(resultChan)
close(errChan)
fmt.Println(results)
fmt.Println(err)
}
游樂場:https ://go.dev/play/p/zA-Py9gDjce 此代碼有效,我得到了我想要的結果,即:
[25 1 4 0 16]
[<nil> <nil> <nil> goroutine 3's error returned <nil>]
我想知道是否有更慣用的方法來實作這一點。我瀏覽了 errgroup 包:https ://pkg.go.dev/golang.org/x/sync/errgroup但在這里找不到可以幫助我的東西。歡迎任何建議。
uj5u.com熱心網友回復:
Waitgroup 在此代碼中是多余的。執行與等待通道結果的回圈完美同步。在所有函式完成作業并從通道中讀取發布的結果之前,代碼不會向前移動。僅當您的函式需要在結果發布到頻道后執行任何作業時,才需要等待組。
我也更喜歡稍微不同的實作。在發布的實作中,我們不會在每次執行函式時都將結果和錯誤都發送到通道中。相反,我們可以只發送成功執行的結果,而在代碼失敗時只發送一個錯誤。
優點是簡化了結果/錯誤處理。我們在沒有nils.
在這個例子中,函式回傳一個數字,我們發送它的默認值0以防出錯。如果零可能是合法的函式執行結果,那么從成功中過濾掉不成功的執行結果可能會很復雜。
與錯誤相同。要檢查我們是否有任何錯誤,我們可以使用簡單的代碼,例如if len(errs) != 0.
package main
import (
"fmt"
)
func processBatch(num int, errChan chan<- error, resultChan chan<- int) {
if num == 3 {
// no need to send result when it is meanenless
// resultChan <- 0
errChan <- fmt.Errorf("goroutine %d's error returned", num)
} else {
square := num * num
resultChan <- square
// no need to send errror when it is nil
// errChan <- nil
}
}
func main() {
batches := [5]int{1, 2, 3, 4, 5}
resultChan := make(chan int)
errChan := make(chan error)
for i := range batches {
go processBatch(batches[i], errChan, resultChan)
}
// use slices instead of arrays because legth varry now
var results []int
var errs []error
// every time function executes it sends singe piece of data to one of two channels
for range batches {
select {
case res := <-resultChan:
results = append(results, res)
case err := <-errChan:
errs = append(errs, err)
}
}
close(resultChan)
close(errChan)
fmt.Println(results)
fmt.Println(errs)
}
https://go.dev/play/p/SYmfl8iGxgD
[25 1 16 4]
[goroutine 3's error returned]
如果您可以使用外部包,我們可以從一些multierr包中獲得好處。例如,github.com/hashicorp/go-multierror。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/493499.html
