errgroup源码

1. 简介

golang为并发执行提供了WaitGroup工具,方便goroutine执行的控制,但是缺少了error的传递和一个goroutine出错,取消其他goroutine执行能力。通过对WaitGroup的进一步封装,就变成了errgroup,可以很好的解决上述问题

2. 核心结构体

type Group struct {
    // context的cancel方法
	cancel func()
    // 控制多个g的执行
	wg sync.WaitGroup
    // 对同时执行的g的数量控制
	sem chan token
    // Once 保证逻辑只执行一次,只接收产生的第一个error
	errOnce sync.Once
    // 第一个产生的error
	err     error
}

Group结构体的核心是WaitGroup, 配合其他字段来完成功能

3. 初始化

func WithContext(ctx context.Context) (*Group, context.Context) {
    // 创建一个可取消的context
	ctx, cancel := context.WithCancel(ctx)
   // 初始化结构体 直接返回
	return &Group{cancel: cancel}, ctx
}

创建一个可取消的context, 复制给Group直接返回

4. 执行逻辑

func (g *Group) Go(f func() error) {
// 使用带缓冲的channel,进行g控制,是阻塞的
	if g.sem != nil {
		g.sem <- token{}
	}

// 使用wg进行控制
	g.wg.Add(1)
	go func() {
// defer 保证 g.done 最终执行
		defer g.done()

// 如果执行方法 返回了err,记录err,执行context的cacenl方法,由其他g根据context的done()自行判断是否需要退出
		if err := f(); err != nil {
			g.errOnce.Do(func() {
				g.err = err
				if g.cancel != nil {
					g.cancel()
				}
			})
		}
	}()
}

Go方法会启动一个协程,使用waitgroup进行控制

5. wait方法

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

使用waitgroup进行等待, 并返回error

6. 对g数量的控制

6.1 SetLimit设置限制数量

func (g *Group) SetLimit(n int) {
	if n < 0 {
		g.sem = nil
		return
	}
	if len(g.sem) != 0 {
		panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", len(g.sem)))
	}
// 设置chan的缓冲长度
	g.sem = make(chan token, n)
}

设置chan的缓冲长度来控制g数量

6.2 Go执行时进行控制

func (g *Group) Go(f func() error) {
    // 设置过则进行判断
	if g.sem != nil {
    // 如果chan满了,则进行阻塞限制下面新g
    // 未满时,不会阻塞执行新g
		g.sem <- token{}
	}

	g.wg.Add(1)
	go func() {}
}

6.3  done方法,标志g执行结束

func (g *Group) done() {
	if g.sem != nil {
       // 取出chan
		<-g.sem
	}
	g.wg.Done()
}

1. g的数量限制通过带缓冲的chan实现的,chan未满时,不阻塞执行新g, 满了时,会阻塞,等待有新g。

2. goroutine执行结束后调用done方法,取出chan,下次再执行Go方法时,就不会阻塞

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值