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 关注
- 103 浏览
添加回答
举报