3 回答

TA貢獻(xiàn)1942條經(jīng)驗(yàn) 獲得超3個(gè)贊
使用錯(cuò)誤通道進(jìn)行同步
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
}
一些注意事項(xiàng):
每個(gè) go 函數(shù)都必須向 添加一個(gè)值。確保它!如果沒有錯(cuò)誤,則寫入(如果沒有錯(cuò)誤,此示例將寫入)。
chErr
nil
chErr
for 循環(huán)必須迭代與啟動(dòng) go 函數(shù)相同的數(shù)量。
for 循環(huán)確保所有函數(shù)都已完成(有或沒有錯(cuò)誤),然后再繼續(xù)。
使用錯(cuò)誤進(jìn)行同步很方便,因?yàn)樗鼘?duì)于所有函數(shù)都是相同的類型。返回類型可能不同。如果我們需要在錯(cuò)誤時(shí)取消,我們無論如何都需要將錯(cuò)誤從goroutines中取回。
使用errgroup
正如 @Зелёный 在注釋中所建議的那樣,這里有一個(gè)使用(仍然)實(shí)驗(yàn)包錯(cuò)誤組的示例:
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
}
一些注意事項(xiàng):
這個(gè)檢查所有錯(cuò)誤,并為您返回第一個(gè)錯(cuò)誤。
如果一個(gè)錯(cuò)誤,它還會(huì)取消剩余的調(diào)用(因此
ctx
)它使用
sync.WaitGroup
缺點(diǎn):它是一個(gè)額外的依賴項(xiàng),因?yàn)樗皇菢?biāo)準(zhǔn)庫(kù)的一部分(尚未)。
使用WaitGroup
還可以使用 a 來等待所有函數(shù)都返回其結(jié)果。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
}
一些注意事項(xiàng):
這里需要 3 個(gè)錯(cuò)誤變量。
您需要在 之后檢查所有3個(gè)錯(cuò)誤變量,使其有點(diǎn)冗長(zhǎng)。
wg.Wait

TA貢獻(xiàn)1803條經(jīng)驗(yàn) 獲得超6個(gè)贊
您還可以使用等待組來等待所有 api 調(diào)用完成,然后再繼續(xù)操作:
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()
}
進(jìn)一步參考也 https://gobyexample.com/waitgroups 和 https://tutorialedge.net/golang/go-waitgroup-tutorial/

TA貢獻(xiàn)1820條經(jīng)驗(yàn) 獲得超9個(gè)贊
如果 a、b 和 c 是不同的類型,則可以嘗試以下方法。interface{}類型只是為了展示如何編碼,你可以根據(jù)自己的要求修改通道類型。
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)
如果所有三個(gè)輸出都處于同一類型,則只需使用單個(gè)通道或使用帶有 select 語句的 forever for 循環(huán)來處理流式處理要求。
- 3 回答
- 0 關(guān)注
- 143 瀏覽
添加回答
舉報(bào)