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 类似。只是封装了 WaitGroup Add()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

errgroup 分析的更多相关文章

  1. drone的pipeline原理与代码分析

    最近的一个项目,需要实现一个工作任务流(task pipeline),基于之前CICD的经验,jenkins pipeline和drone的pipeline进入候选. drone是基于go的cicd解 ...

  2. 十二. Go并发编程--sync/errGroup

    一.序 这一篇算是并发编程的一个补充,起因是当前有个项目,大概の 需求是,根据kafka的分区(partition)数,创建同等数量的 消费者( goroutine)从不同的分区中消费者消费数据,但是 ...

  3. alias导致virtualenv异常的分析和解法

    title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...

  4. 火焰图分析openresty性能瓶颈

    注:本文操作基于CentOS 系统 准备工作 用wget从https://sourceware.org/systemtap/ftp/releases/下载最新版的systemtap.tar.gz压缩包 ...

  5. 一起来玩echarts系列(一)------箱线图的分析与绘制

    一.箱线图 Box-plot 箱线图一般被用作显示数据分散情况.具体是计算一组数据的中位数.25%分位数.75%分位数.上边界.下边界,来将数据从大到小排列,直观展示数据整体的分布情况. 大部分正常数 ...

  6. 应用工具 .NET Portability Analyzer 分析迁移dotnet core

    大多数开发人员更喜欢一次性编写好业务逻辑代码,以后再重用这些代码.与构建不同的应用以面向多个平台相比,这种方法更加容易.如果您创建与 .NET Core 兼容的.NET 标准库,那么现在比以往任何时候 ...

  7. UWP中新加的数据绑定方式x:Bind分析总结

    UWP中新加的数据绑定方式x:Bind分析总结 0x00 UWP中的x:Bind 由之前有过WPF开发经验,所以在学习UWP的时候直接省略了XAML.数据绑定等几个看着十分眼熟的主题.学习过程中倒是也 ...

  8. 查看w3wp进程占用的内存及.NET内存泄露,死锁分析

    一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...

  9. ZIP压缩算法详细分析及解压实例解释

    最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据 ...

随机推荐

  1. Assignment4:闰年判断输入异常时的处理方法

    一.问题描述 在输入界面输入年份,界面返回是否为闰年. 判断依据为:输入的数字可以被4整除但不可以被100整除 || 输入的数字可以被400整除 如果输入为数字以外的其他字符,会抛出异常.那么如何防止 ...

  2. PostgreSQL: Rename a User

    Syntax The syntax to rename a user using the ALTER USER statement in PostgreSQL is: ALTER USER user_ ...

  3. ogr ogr2ogr 矢量数据格式转换 ogrinfo 矢量数据图层信息操作 ogr gdal的一部分 gdal 命令行 库操作

  4. spring-data-mongodb中的MongoTemplate与MongoRepository及推荐

    SpringData支持两种关系数据存储技术: JDBCJPA ● SpringData 方法定义JPA规范: 1. 不是随便声明的,而需要符合一定的规范2. 查询方法以find | read | g ...

  5. 使用layui框架的select获取选中的值

    在使用时需要注意:select标签的外层需要加上类名".layui-form" 接下来就是根据需求来改变下拉框的内容了,直接给select的option重新赋一次值,记得加上对应的 ...

  6. esxi上为基于LVM的centos7的根目录扩容

    概念:据说默认centos都是基于LVM的 LVM:LVM是逻辑盘卷管理(Logical Volume Manager)的简称,它是Linux环境下对磁盘分区进行管理的一种机制. LVM 更加详细的说 ...

  7. centos和windows添加路由命令记录

    # 默认路由做香港出口route add default gw 192.168.10.33route add default gw 192.168.10.1 # 删除默认路由# route del d ...

  8. shell编程系列2--字符串的处理

    shell编程系列2--字符串的处理 字符串的处理 .计算字符串的长度 方法1 ${#string} 方法2 expr length "$string" (如果string中间有空 ...

  9. 多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中【我】

    多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中 package com.xxx.xx.reve.service; import java.util.ArrayL ...

  10. 【DataBase】H2 DateBase的拓展使用

    连接模式 支持以下连接模式: 嵌入模式(使用JDBC的本地连接) 服务器模式(使用JDBC或ODBC over TCP / IP进行远程连接) 混合模式(同时本地和远程连接) 嵌入模式 在嵌入模式下, ...