errgroup 分析

errgroup 在 WaitGroup 的基础上实现子协程错误传递, 同时使用 context 控制协程的生命周期。

使用

errgroup 的使用非常简单

package main

import (
    "context"
    "fmt"
    "time"

    "golang.org/x/sync/errgroup"
)

func main() {
    group, _ := errgroup.WithContext(context.Background())
    for i := 0; i < 5; i++ {
        index := i
        group.Go(func() error {
            fmt.Printf("start to execute the %d gorouting\n", index)
            time.Sleep(time.Duration(index) * time.Second)
            if index%2 == 0 {
                return fmt.Errorf("something has failed on grouting:%d", index)
            }
            fmt.Printf("gorouting:%d end\n", index)
            return nil
        })
    }
    if err := group.Wait(); err != nil {
        fmt.Println(err)
    }
}

输出

输出结果如下:

start to execute the 0 gorouting
start to execute the 3 gorouting
start to execute the 2 gorouting
start to execute the 1 gorouting
start to execute the 4 gorouting
gorouting:1 end
gorouting:3 end
something has failed on grouting:0

代码分析

不管是否有协程执行失败, wait()都要等待所有协程执行完成

使用方法与 WaitGroup 类似。只是封装了 WaitGroupAdd()Wait()方法。

  • 首先传递 context 初始化 errgroup 对象
  • 每一个 group.Go() 都会新启一个协程, Go()函数接受一个 func() error 函数类型
  • 使用 Wait()方法阻塞主协程,直到所有子协程执行完成

分析

errGroup 的结构如下:

type Group struct {
  cancel  func()             //context cancel()
    wg      sync.WaitGroup       
    errOnce sync.Once          //只会传递第一个出现错的协程的 error
    err     error              //传递子协程错误
}

withContext

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

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

小结

  • errgroup 可以捕获和记录子协程的错误(只能记录最先出错的协程的错误)
  • errgroup 可以控制协程并发顺序。确保子协程执行完成后再执行主协程
  • errgroup 可以使用 context 实现协程撤销。或者超时撤销。子协程中使用 ctx.Done()来获取撤销信号

参考

errgroup godoc

转载于:https://www.cnblogs.com/jssyjam/p/11193822.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值