理解 Go 语言的分组操作

        共享资源保护、任务编排和消息传递是 Go 并发编程中常见的场景,而分组执行一批相同的或类似的任务则是任务编排中的一类情形。下面我们专门介绍分组编排的一些常用场景和同步原语,主要用来处理一组任务。我们先来介绍一个非常常用的同步原语,即 ErrGroup。

1. ErrGroup

        ErrGroup 是 Go 官方提供的一个同步扩展库。我们经常会遇到需要将一个通用的父任务拆分成几个小任务并发执行的场景,其实,这样做可以有效地提高程序的并发度.

1.1 ErrGroup 的基本用法

        golang.org/x/sync/errgroup 包下定义了一个 Group struct, 它就是我们要介绍的 ErrGroup 同步原语,其底层是基于 WaitGroup 实现的。

        在使用 ErrGroup 时,我们要用到 5  个方法,分别是 WithContext、Go、TryGo、Wait 和 SetLimit。

        1. WithContext

        在创建一个 Group 对象时,需要使用 WithContext 方法:

func WithContext(ctx context.Context) (*Group,context.Context)

        该方法传入一个 Context, 返回一个 Group 以及一个派生的 Context。

        这个派生的 Context 会在下面两种情况下被取消:

  • 传给 Go 方法的函数 f 第一次返回非空 (nil) 的 error。
  • Wait 方法第一次返回

        Group 的零值也是合法的。也就是不通过 WithContext 生成 Group, 而是使用它的零值。这是可以的,只不过这样就没有可以监控是否可以撤销的 Context 了。

        另外需要注意的是,如果传递给 WithContext 的 ctx 参数是一个可撤销的 Context, 那么它被撤销时并不会中止正在执行的子任务。

        2. Go

        Go 方法的签名如下:

func (g *Group) Go(f func() error)

        该方法在新的 goroutine 中调用函数 f,该函数可以返回 error。

        如果当前 Group 中活跃的 goroutine 的数量超过了设置的数量限制,那么它会被阻塞,直到有可用的新的 goroutine 加入。

        如果调用函数 f 第一次返回非空的 error ,则会撤销这个 Group 的 Context, 这给调用者留下了想象的空间。如果这个 Group 是使用 WithContext 创建的,那么 Wait 方法会返回这个 error。

        Go 方法被并发调用时,函数 f  可以是不一样的,只要是符合其签名的函数,就都可以被当作参数,并没有规定同一个 Group 必须使用相同的函数。

        3. TryGo

        TryGo 方法的签名如下:

func (g *Group) TryGo(f func() error) bool

        TryGo 方法尝试创建新的 Group 来执行函数 f, 不过要求当前活跃的 goroutine 的数量不能超过限制,否则直接返回,不会被阻塞。

        返回的结果指示函数 f 是否被执行,其中 true 表示成功启动 goroutine 来执行函数 f ,false 表示函数 f 没有被执行。 

        4. Wait

        Wait 方法的签名如下:

func (g *Group) Wait() error

        Wait 方法等待所有的 goroutine 都执行完成才返回,否则一直被阻塞。如果函数 f 执行时返回了非空的 error,那么 Wait 方法将会把第一个非空的 error 返回。 

        5. SetLimit

        SetLimit 方法的签名如下:

func (g *Group) SetLimit(n int)

        该方法限制同时最多有 n 个活跃的 goroutine 执行函数 f 。n 为负值代表 goroutine 的数量没有限制。

        设置完毕后,后续活跃的 goroutine 的数量不能超过这个限制。如果有活跃的 goroutine,则不能进行限制。

        ErrGroup 由 WaitGroup、信号量(用channel实现)、Once、Context 组合而成。信号量用于控制活跃的  goroutine 的数量, WaitGroup 用于等待所有的任务执行完成,Once 用于控制设置 error, Context 用于控制撤销以及 error 的发生。

1.2 ErrGroup 使用示例

        1. 返回第一个错误

        我们先来看一个简单的例子。在这个例子中启动了三个任务,其中第二个子任务执行失败,其他两个子任务执行成功。只有在这三个子任务都执行完成后,group.Wait 才会返回第二个子任务的错误。

package main

import (
	"errors"
	"fmt"
	"time"
	
	"golang.org/x/sync/errgroup"
)

func main(){
	var g errgroup.Group
	
	// 启动第一个子任务,它执行成功
	g.Go(func() error{
		time.Sleep(5 *time.Second)
		fmt.Println("exec #1")
		return nil
	})
	
	// 启动第二个子任务,它执行失败
	g.Go(
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mindfulness code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值