g := &errgroup.Group{}
g.Go(func() error {
return nil
})
g.Go(func() error {
return nil
})
if err:=g.Wait();err!=nil {
panic(err)
}
在需要开启协程并发请求的时候,通常可以通过errgroup包封装的Group进行调用,不用再去关注Add多少个协程和什么时候Done,在每个Go方法中已经封装好一对一了
func (g *Group) Go(f func() error) {
g.wg.Add(1)
go func() {
defer g.wg.Done()
if err := f(); err != nil {
g.errOnce.Do(func() {
g.err = err
if g.cancel != nil {
g.cancel()
}
})
}
}()
}
调用Go方法后再调用Wait方法等待协程运行结束即可。
func (g *Group) Wait() error {
g.wg.Wait()
if g.cancel != nil {
g.cancel()
}
return g.err
}
但是上面的Wait方法只给我们返回了错误,具体是哪个Go方法里面出现错误,我们只能通过日志打印出来才知道,并且模调判断服务调用属于哪种错误是根据返回码来的,这时候我们可以改造一下Group,让它给我们同时返回错误码和错误
package main
import (
"fmt"
"sync"
)
// Group 结构体
type Group struct {
wg sync.WaitGroup
errOnce sync.Once
ret int32
err error
}
// Wait wait
func (obj *Group) Wait() (int32, error) {
obj.wg.Wait()
if obj.ret != 0 || obj.err != nil {
return obj.ret, obj.err
}
return 0, nil
}
// Go 执行方法
func (obj *Group) Go(f func() (int32, error)) {
obj.wg.Add(1)
go func() {
defer obj.wg.Done()
ret, err := f()
if err != nil || ret != 0 {
obj.errOnce.Do(func() {
obj.err = err
obj.ret = ret
})
}
}()
}
func main() {
test01()
}
func test01() {
g := &Group{}
g.Go(func() (int32, error) {
fmt.Println("g1")
return 0, nil
})
g.Go(func() (int32, error) {
fmt.Println("g2")
return 2, nil
})
g.Go(func() (int32, error) {
fmt.Println("g3")
return 3, fmt.Errorf("g3 err")
})
if ret, err := g.Wait(); ret != 0 || err != nil {
fmt.Printf("ret:%d err:%+v", ret, err)
return
}
fmt.Println("没有错误")
}
对于错误码的处理,和错误一样,都是通过Once只处理一次,不会覆盖
网友评论