go中errgroup源码解读
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
中,来实现对使用errgroup
的ctx
启动的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、如果包装了context
的CancelFunc
,在出错的时候进行退出操作。
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、如果包装了context
的CancelFunc
,在出错的时候进行退出操作;
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源码解读的更多相关文章
- go中panic源码解读
panic源码解读 前言 panic的作用 panic使用场景 看下实现 gopanic gorecover fatalpanic 总结 参考 panic源码解读 前言 本文是在go version ...
- go中waitGroup源码解读
waitGroup源码刨铣 前言 WaitGroup实现 noCopy state1 Add Wait 总结 参考 waitGroup源码刨铣 前言 学习下waitGroup的实现 本文是在go ve ...
- etcd中watch源码解读
etcd中watch的源码解析 前言 client端的代码 Watch newWatcherGrpcStream run newWatchClient serveSubstream server端的代 ...
- java中jdbc源码解读
在jdbc中一个重要的接口类就是java.sql.Driver,其中有一个重要的方法:Connection connect(String url, java.util.Propeties info); ...
- 【原】Spark中Job的提交源码解读
版权声明:本文为原创文章,未经允许不得转载. Spark程序程序job的运行是通过actions算子触发的,每一个action算子其实是一个runJob方法的运行,详见文章 SparkContex源码 ...
- HttpServlet中service方法的源码解读
前言 最近在看<Head First Servlet & JSP>这本书, 对servlet有了更加深入的理解.今天就来写一篇博客,谈一谈Servlet中一个重要的方法-- ...
- AbstractCollection类中的 T[] toArray(T[] a)方法源码解读
一.源码解读 @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { //size为集合的大小 i ...
- go 中 sort 如何排序,源码解读
sort 包源码解读 前言 如何使用 基本数据类型切片的排序 自定义 Less 排序比较器 自定义数据结构的排序 分析下源码 不稳定排序 稳定排序 查找 Interface 总结 参考 sort 包源 ...
- Mybatis源码解读-SpringBoot中配置加载和Mapper的生成
本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...
随机推荐
- 一、Jmeter进行Mysql数据库的压测
1.首先需要安装配置mysql数据库连接驱动:mysql-connector-java-5.1.28.jar 1.1 网上很多资源,可自行下载: 1.2 下载完成后,分别将该jra包,存放到:jmet ...
- 国产网络测试仪MiniSMB - 如何配置VLAN数据流
国产网络测试仪MiniSMB(www.minismb.com)是复刻smartbits的IP网络性能测试工具,是一款专门用于测试智能路由器,网络交换机的性能和稳定性的软硬件相结合的工具.可以通过此以太 ...
- HBuilderX All In One
HBuilderX All In One uni-app https://uniapp.dcloud.io/quickstart-hx 目录结构 一个uni-app工程,默认包含如下目录及文件: $ ...
- Ant-design-vue—— 表单输入框输入很卡问题
参考:https://blog.csdn.net/weixin_43905402/article/details/106074435 我的问题:vue项目中使用ant-design-vue,表单中输入 ...
- UTM & User Tracking Message
UTM & User Tracking Message utm_source https://marketingplatform.google.com/about/resources/link ...
- PIP & Python packages management
PIP & Python packages management $ python3 --version # OR $ python3 -V # Python 3.7.3 $ pip --ve ...
- npx & yarn & npm
npx & yarn & npm React Redux App https://reactjs.org/ https://github.com/facebook/create-rea ...
- Contributor License Agreement
Contributor License Agreement CLA https://cla.js.foundation/lodash/lodash?pullRequest=4756 https://g ...
- IndexedDB All In One
IndexedDB All In One https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API https://develope ...
- 扫码登录 & 实现原理
扫码登录 & 实现原理 二维码扫描登录是什么原理? https://time.geekbang.org/dailylesson/detail/100044032 xgqfrms 2012-20 ...