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自动装载机制,再看此 ...
随机推荐
- Codeforces Round #649 (Div. 2) B. Most socially-distanced subsequence (数学,差分)
题意:有一长度为\(n\)的数组,求一子序列,要求子序列中两两差的绝对值最大,并且子序列尽可能短. 题解:将数组看成坐标轴上的点,其实就是求每个单调区间的端点,用差分数组来判断单调性. 代码: #in ...
- Entity Framework (EF) Core学习笔记 1
1. Entity Framework (EF) Core 是轻量化.可扩展.开源和跨平台的数据访问技术,它还是一 种对象关系映射器 (ORM),它使 .NET 开发人员能够使用面向对象的思想处理数据 ...
- 洛谷P1144-最短路计数-最短路变形
洛谷P1144-最短路计数 题目描述: 给出一个\(N\)个顶点\(M\)条边的无向无权图,顶点编号为\(1-N\).问从顶点\(1\)开始,到其他每个点的最短路有几条. 思路: \(Dijkstra ...
- k8s-2-集成apollo配置中心
主题: 在k8s中集成Apollo配置中心 架构图 一.配置中心概述 配置的几种方式 本课讲得是基于配置中心数据库实现 配置管理的现状 常见的配置中心 主讲:k8s configmap,apollo ...
- Nginx基础 - HTTPS安全web服务
1.HTTPS配置语法 Syntax: ssl on | off; Default: ssl off; Context: http, server Syntax: ssl_certificate fi ...
- Zabbix 监控项更多用法
监控服务端口状态 配置 Zabbix 提供的检测器 配置自定义值映射 查看监控项数据状态 触发器配置 自定义监控项 TCP 11 种状态 TCP 11 种状态 LISTEN - 侦听来自远方TCP端口 ...
- IGS OPC UA 配置
igs项目-右键属性-选择OPC UA,如图配置 ,其他默认 如果打开的是IGS-administration,在右下角会有通知栏图标,右键图标选择 OPC UA 配置 添加服务器节点,网络适配器选择 ...
- canvas实现简易时钟效果
代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8& ...
- CDN 工作原理剖析
CDN 工作原理剖析 CDN / Content Delivery Network / 内容分发网络 https://www.cloudflare.com/zh-cn/learning/cdn/wha ...
- Fetch & POST
Fetch & POST fetch( `http://10.1.5.202/deploy/http/send/viewtree`, { method: "POST", m ...