3 回答

TA貢獻1942條經驗 獲得超3個贊
使用錯誤通道進行同步
func sampleAPI(w http.ResponseWriter, r *http.Request) {
chErr := make(chan error)
var a correctType
go func() {
var err error
a, err = getFromATable()
chErr <- err
}()
var b correctType
go func() {
var err error
b, err = getFromBTable()
chErr <- err
}()
var c correctType
go func() {
var err error
c, err = getFromCTable()
chErr <- err
}()
var err error
for i := 0; i < 3; i++ {
if r := <-chErr; r != nil {
err = r
}
}
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
// etc.
return
}
// continue to do stuff with a, b, c
}
一些注意事項:
每個 go 函數都必須向 添加一個值。確保它!如果沒有錯誤,則寫入(如果沒有錯誤,此示例將寫入)。
chErr
nil
chErr
for 循環必須迭代與啟動 go 函數相同的數量。
for 循環確保所有函數都已完成(有或沒有錯誤),然后再繼續。
使用錯誤進行同步很方便,因為它對于所有函數都是相同的類型。返回類型可能不同。如果我們需要在錯誤時取消,我們無論如何都需要將錯誤從goroutines中取回。
使用errgroup
正如 @Зелёный 在注釋中所建議的那樣,這里有一個使用(仍然)實驗包錯誤組的示例:
func sampleAPI(w http.ResponseWriter, r *http.Request) {
g, ctx := errgroup.WithContext(context.TODO())
var a correctType
g.Go(func() (err error) {
a, err = getFromATable(ctx)
return err
})
var b correctType
g.Go(func() (err error) {
b, err = getFromBTable(ctx)
return err
})
var c correctType
g.Go(func() (err error) {
c, err = getFromCTable(ctx)
return err
})
if err := g.Wait(); err != nil {
w.WriteHeader(http.StatusInternalServerError)
// etc.
return
}
// continue to do stuff with a, b, c
}
一些注意事項:
這個檢查所有錯誤,并為您返回第一個錯誤。
如果一個錯誤,它還會取消剩余的調用(因此
ctx
)它使用
sync.WaitGroup
缺點:它是一個額外的依賴項,因為它不是標準庫的一部分(尚未)。
使用WaitGroup
還可以使用 a 來等待所有函數都返回其結果。sync.WaitGroup
func sampleAPI(w http.ResponseWriter, r *http.Request) {
var wg sync.WaitGroup
wg.Add(3)
var a correctType
var errA error
go func() {
defer wg.Done()
a, errA = getFromATable()
}()
var b correctType
var errB error
go func() {
defer wg.Done()
b, errB = getFromBTable()
}()
var c correctType
var errC error
go func() {
defer wg.Done()
c, errC = getFromCTable()
}()
wg.Wait()
if errA != nil {
w.WriteHeader(http.StatusInternalServerError)
// etc.
return
}
if errB != nil {
w.WriteHeader(http.StatusInternalServerError)
// etc.
return
}
if errC != nil {
w.WriteHeader(http.StatusInternalServerError)
// etc.
return
}
// continue to do stuff with a, b, c
}
一些注意事項:
這里需要 3 個錯誤變量。
您需要在 之后檢查所有3個錯誤變量,使其有點冗長。
wg.Wait

TA貢獻1803條經驗 獲得超6個贊
您還可以使用等待組來等待所有 api 調用完成,然后再繼續操作:
func sampleAPI(w http.ResponseWriter, r *http.Request) {
var res1, res2, res3 myCustomType
var err1, err2, err2 error
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
res1, err1 = getFromATable(); //1
}()
go func() {
defer wg.Done()
res2, err2 = getFromBTable(); //2
}()
go func() {
defer wg.Done()
res3, err3 = getFromXTable(); //3
}()
wg.Wait()
}
進一步參考也 https://gobyexample.com/waitgroups 和 https://tutorialedge.net/golang/go-waitgroup-tutorial/

TA貢獻1820條經驗 獲得超9個贊
如果 a、b 和 c 是不同的類型,則可以嘗試以下方法。interface{}類型只是為了展示如何編碼,你可以根據自己的要求修改通道類型。
aCh := make(chan interface{})
bCh := make(chan interface{})
cCh := make(chan interface{})
defer close(aCh)
defer close(bCh)
defer close(cCh)
go func() {
a, _ := GetFromATable()
aCh <- a
}()
go func() {
b, _ := GetFromBTable()
bCh <- b
}()
go func() {
c, _ := GetFromCTable()
cCh <- c
}()
fmt.Println(<- aCh, <- bCh, <- cCh)
如果所有三個輸出都處于同一類型,則只需使用單個通道或使用帶有 select 語句的 forever for 循環來處理流式處理要求。
- 3 回答
- 0 關注
- 144 瀏覽
添加回答
舉報