errgroup

前言

来看下errgroup的实现

如何使用

func main() {
var eg errgroup.Group eg.Go(func() error {
return errors.New("test1")
}) eg.Go(func() error {
return errors.New("test2")
}) if err := eg.Wait(); err != nil {
fmt.Println(err)
}
}

类比于waitgroup,errgroup增加了一个对goroutine错误收集的作用。

不过需要注意的是:

errgroup返回的第一个出错的goroutine抛出的err

errgroup中还可以加入context

func main() {
eg, ctx := errgroup.WithContext(context.Background()) eg.Go(func() error {
// test1函数还可以在启动很多goroutine
// 子节点都传入ctx,当test1报错,会把test1的子节点一一cancel
return test1(ctx)
}) eg.Go(func() error {
return test1(ctx)
}) if err := eg.Wait(); err != nil {
fmt.Println(err)
}
} func test1(ctx context.Context) error {
return errors.New("test2")
}

实现原理

代码很简单

type Group struct {
// 一个取消的函数,主要来包装context.WithCancel的CancelFunc
cancel func() // 还是借助于WaitGroup实现的
wg sync.WaitGroup // 使用sync.Once实现只输出第一个err
errOnce sync.Once // 记录下错误的信息
err error
}

还是在WaitGroup的基础上实现的

WithContext

// 返回一个被context.WithCancel重新包装的ctx

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

里面使用了context,通过context.WithCancel对传入的context进行了包装

WithCancel函数返回的CancelFunc被调用或者是父节点的done channel被关闭(父节点的 CancelFunc 被调用),此 context(子节点)的 done channel 也会被关闭。

errgroup把返回的CancelFunc包进了自己的cancel中,来实现对使用errgroupctx启动的goroutine的取消操作。

Go

// 启动取消阻塞的goroutine
// 记录第一个出错的goroutine的err信息
func (g *Group) Go(f func() error) {
// 借助于waitgroup实现
g.wg.Add(1) go func() {
defer g.wg.Done() // 执行出错
if err := f(); err != nil {
// 通过sync.Once记录下第一个出错的err信息
g.errOnce.Do(func() {
g.err = err
// 如果包装了cancel,也就是context的CancelFunc,执行退出操作
if g.cancel != nil {
g.cancel()
}
})
}
}()
}

1、借助于waitgroup实现对goroutine阻塞;

2、通过sync.Once记录下,第一个出错的goroutine的错误信息;

3、如果包装了contextCancelFunc,在出错的时候进行退出操作。

Wait

// 阻塞所有的通过Go加入的goroutine,然后等待他们一个个执行完成
// 然后返回第一个出错的goroutine的错误信息
func (g *Group) Wait() error {
// 借助于waitgroup实现
g.wg.Wait()
// 如果包装了cancel,也就是context的CancelFunc,执行退出操作
if g.cancel != nil {
g.cancel()
}
return g.err
}

1、借助于waitgroup实现对goroutine阻塞;

2、如果包装了contextCancelFunc,在出错的时候进行退出操作;

3、抛出第一个出错的goroutine的错误信息。

错误的使用

不过工作中发现一个errgroup错误使用的例子

func main() {
eg := errgroup.Group{}
var err error
eg.Go(func() error {
// 处理业务
err = test1()
return err
}) eg.Go(func() error {
// 处理业务
err = test1()
return err
}) if err = eg.Wait(); err != nil {
fmt.Println(err)
}
} func test1() error {
return errors.New("test2")
}

很明显err被资源竞争了

$ go run -race main.go
==================
WARNING: DATA RACE
Write at 0x00c0000801f0 by goroutine 8:
main.main.func2()
/Users/yj/Go/src/Go-POINT/sync/errgroup/main.go:23 +0x97
...

总结

errgroup相比比较简单,不过需要先弄明白waitgroup,context以及sync.Once,主要是借助这几个组件来实现的。

errgroup可以带携带context,如果包装了context,会使用context.WithCancel进行超时,取消或者一些异常的情况

go中errgroup源码解读的更多相关文章

  1. go中panic源码解读

    panic源码解读 前言 panic的作用 panic使用场景 看下实现 gopanic gorecover fatalpanic 总结 参考 panic源码解读 前言 本文是在go version ...

  2. go中waitGroup源码解读

    waitGroup源码刨铣 前言 WaitGroup实现 noCopy state1 Add Wait 总结 参考 waitGroup源码刨铣 前言 学习下waitGroup的实现 本文是在go ve ...

  3. etcd中watch源码解读

    etcd中watch的源码解析 前言 client端的代码 Watch newWatcherGrpcStream run newWatchClient serveSubstream server端的代 ...

  4. java中jdbc源码解读

    在jdbc中一个重要的接口类就是java.sql.Driver,其中有一个重要的方法:Connection connect(String url, java.util.Propeties info); ...

  5. 【原】Spark中Job的提交源码解读

    版权声明:本文为原创文章,未经允许不得转载. Spark程序程序job的运行是通过actions算子触发的,每一个action算子其实是一个runJob方法的运行,详见文章 SparkContex源码 ...

  6. HttpServlet中service方法的源码解读

    前言     最近在看<Head First Servlet & JSP>这本书, 对servlet有了更加深入的理解.今天就来写一篇博客,谈一谈Servlet中一个重要的方法-- ...

  7. AbstractCollection类中的 T[] toArray(T[] a)方法源码解读

    一.源码解读 @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { //size为集合的大小 i ...

  8. go 中 sort 如何排序,源码解读

    sort 包源码解读 前言 如何使用 基本数据类型切片的排序 自定义 Less 排序比较器 自定义数据结构的排序 分析下源码 不稳定排序 稳定排序 查找 Interface 总结 参考 sort 包源 ...

  9. Mybatis源码解读-SpringBoot中配置加载和Mapper的生成

    本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...

随机推荐

  1. 一、Jmeter进行Mysql数据库的压测

    1.首先需要安装配置mysql数据库连接驱动:mysql-connector-java-5.1.28.jar 1.1 网上很多资源,可自行下载: 1.2 下载完成后,分别将该jra包,存放到:jmet ...

  2. 国产网络测试仪MiniSMB - 如何配置VLAN数据流

    国产网络测试仪MiniSMB(www.minismb.com)是复刻smartbits的IP网络性能测试工具,是一款专门用于测试智能路由器,网络交换机的性能和稳定性的软硬件相结合的工具.可以通过此以太 ...

  3. HBuilderX All In One

    HBuilderX All In One uni-app https://uniapp.dcloud.io/quickstart-hx 目录结构 一个uni-app工程,默认包含如下目录及文件: $ ...

  4. Ant-design-vue—— 表单输入框输入很卡问题

    参考:https://blog.csdn.net/weixin_43905402/article/details/106074435 我的问题:vue项目中使用ant-design-vue,表单中输入 ...

  5. UTM & User Tracking Message

    UTM & User Tracking Message utm_source https://marketingplatform.google.com/about/resources/link ...

  6. PIP & Python packages management

    PIP & Python packages management $ python3 --version # OR $ python3 -V # Python 3.7.3 $ pip --ve ...

  7. npx & yarn & npm

    npx & yarn & npm React Redux App https://reactjs.org/ https://github.com/facebook/create-rea ...

  8. Contributor License Agreement

    Contributor License Agreement CLA https://cla.js.foundation/lodash/lodash?pullRequest=4756 https://g ...

  9. IndexedDB All In One

    IndexedDB All In One https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API https://develope ...

  10. 扫码登录 & 实现原理

    扫码登录 & 实现原理 二维码扫描登录是什么原理? https://time.geekbang.org/dailylesson/detail/100044032 xgqfrms 2012-20 ...