errgroup 包
golang.org/x/sync/errgroup

底层通过 waitgroup 来控制让所有其他协程运行完主协程 wait 才会被放行

底层通过 context 的只读 channel 来管控子协程的生命周期,如果有一个子协程有 error 返回,那么 context 就会被 cancel

结构体 group
type Group struct {
	cancel func()

	wg sync.WaitGroup

	errOnce sync.Once
	err     error
}
函数 WithContext

WithContext 来生成 group 和 context

func WithContext(ctx context.Context) (*Group, context.Context) {
	ctx, cancel := context.WithCancel(ctx)
	return &Group{cancel: cancel}, ctx
}
函数 Wait

Wait 函数在主协程中通过 err 来判定子协程是否有 err 出现

func (g *Group) Wait() error {
	g.wg.Wait()
	if g.cancel != nil {
		g.cancel()
	}
	return g.err
}
函数 Go

可以开启多协程,其中接受一个返回一个 err 的函数

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()
            }
         })
      }
   }()
}