Go Sync并发包之errgroup

news2024/12/24 20:22:12

你是否写过一个函数,它之所以很长,是因为它要完成很多任务,即使这些任务之间并不相互依赖? 你是否写过一个很长的函数,因为它要完成很多任务,即使这些任务并不相互依赖?我就遇到过这种情况。

想想看,你有一个函数可以做 3 件事:

  • 按用户 ID 从数据库中获取用户详细信息。
  • 调用外部服务,按用户 ID 获取用户最近的活动信息
  • 访问日志服务,按用户 ID 获取用户上次登录的详细信息
func FetchUserData(userID string) error {
    g := errgroup.Group{}
    
	// 获取用户详细信息
    userDetail, _ := fetchUserDetails(userID)
	// 获取用户活动
    userAct, _ := fetchUserActivity(userID)
    // 获取用户登录详细信息
    userLoginInfo, _ := fetchUserLoginDetails(userID)

    // ...
}

所有这些任务都只需要用户 ID,而不使用其他任务的数据。

您可以尝试使用 goroutines 来实现这一点,但您需要自己处理细节问题。让我们来回答这些问题:

  • 同步:如何确保一切完成?
  • 错误处理:如果一项任务出错,你该怎么办?或者三项任务中有两项不成功?
  • 取消:如果一个任务出现问题,如何停止所有其他正在运行的程序?
  • 限制:你是否考虑过限制同时运行多少个 goroutines?
  • 可重复使用:一旦找到解决方案,如何在类似情况下再次使用?

1.什么是 errgroup?

errgroup 软件包可让您同时处理多项任务。

通过它,可以轻松地以安全的方式一起运行,保持同步,处理错误,并控制何时停止 goroutines。下面是一个如何使用它的快速示例:

func FetchUserData() error {
	g := errgroup.Group{}

	// 获取用户详细信息
	g.Go(func() error {
		time.Sleep(1 * time.Second)
		fmt.Println("Fetched user details...")
		return nil
	})

    // 获取用户活动
    g.Go(func() error {
		time.Sleep(1 * time.Second)
		fmt.Println("Fetched user activity...")
		return nil
	})

	// 获取用户登录详细信息
	g.Go(func() error {
		time.Sleep(2 * time.Second)
		fmt.Println("Fetched user login details...")
		return nil
	})

	// 等待所有goroutines完成并返回第一个错误 (如果有)
	return g.Wait()
}

因此,errgroup 的工作就是运行这些任务,并通过 g.Wait() 等待任务结束,我们需要做的就是添加任务。
什么是 errgroup?

当你有很多任务时,比如 10 项、20 项甚至更多,这种方法就非常有用。

但有一点需要注意,如果不加以控制,同时运行过多的程序会占用资源。我们该如何处理呢?让我们在下一节中探讨。"

2.SetLimit:限制程序运行次数

这个软件包为我们提供了一种限制同时运行的 goroutines 数量的方法,让我们看看如何使用它:

func FetchUserData() error {
    g := errgroup.Group{}

    // 将限制设置为2
    g.SetLimit(2)

    // 获取用户详细信息
    g.Go(func() error {
        time.Sleep(1 * time.Second)
        fmt.Println("Fetched user details...")
        return nil
    })

    // 获取用户活动
    g.Go(func() error {
        time.Sleep(1 * time.Second)
        fmt.Println("Fetched user activity...")
        return nil
    })

    // 获取用户登录详细信息
    g.Go(func() error {
        time.Sleep(2 * time.Second)
        fmt.Println("Fetched user login details...")
        return nil
    })

    // 等待所有goroutines完成并返回第一个错误 (如果有)
    return g.Wait()
}

这样做可以确保只有 2 个程序同时运行。试试看,前两个任务会同时显示信息,而第三个任务会在启动 3 秒后显示信息。
SetLimit:限制程序数目

"设置限值后可以更改吗?

答案是肯定的,但要小心。

如果任何 goroutine 正在运行,试图更改限制将导致 errgroup.SetLimit() 异常。

现在,让我们再想一想,如果 errgroup 中已经有 50 个 goroutines,而你不想再添加更多的 goroutines,该怎么办?

3.TryGo:添加快速程序的受控方法

TryGo 与 Go 函数有相似之处,但它提供了一种细致入微的方法来处理 errgroup 中的 goroutine。具体来说,如果当前计数达到设定的限制,它就会阻止添加新的
goroutine

TryGo 的签名有点与众不同:

// TryGo: 检查并添加 goroutine
func (g *Group) TryGo(fn func () error) bool

// Go: 只需添加一个 goroutine
func (g *Group) Go(fn func () error)

如果使用 TryGo,并成功将 goroutine 添加到 errgroup,它将通过返回 true 来传达成功。如果不成功,则返回 false。

但有趣的地方就在这里。

当一个 errgroup 已满时,errgroup.Go() 会阻塞直到一个 goroutine 结束,然后再添加一个新的,相反,errgroup.TryGo() 不会等待。如果 errgroup 已满,TryGo
会立即返回 false。

4.WithContext:处理取消

如果其中一个程序出错,如何停止所有正在运行的程序,从而避免浪费资源?

WithContext 函数用于创建新的 errgroup 和 context :

erg, ctx := errgroup.WithContext(context.Background())

该函数为您提供context,但不提供取消函数,因此您无法自行停止context。

"如果出现错误,errgroup 会为我停止所有程序吗?

不,errgroup 会取消上下文,但不会停止 goroutines。其余的 goroutines 会继续运行,直到完成为止,除非你这样做:

func main() {
  g, ctx := errgroup.WithContext(context.Background())
  
  g.Go(func() error { return fetchUserDetails(ctx) })
  g.Go(func() error { return fetchUserActivity(ctx) })
  g.Go(func() error { return fetchUserPaymentHistory(ctx) })
  
  // Wait for tasks to finish and print the error
  if err := g.Wait(); err != nil {
    fmt.Printf("Encountered an error: %v\n", err)
  }
}

让这些任务依赖于上下文非常重要。因此,当上下文取消时,所有 goroutines 也将停止。

接下来,我将谈谈 Errgroup 的功能:Errgroup Explained:了解其内部运作。

这种方法不仅可以减少额外的代码,而且还提供了一种处理错误和控制 goroutines 生命周期的有效方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1621626.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s集群CD工具-ArgoCD

ArgoCD是什么 Argo CD 是 Kubernetes 的声明式 GitOps 持续交付工具。应用程序定义、配置和环境应该是声明性的和版本控制的。应用程序部署和生命周期管理应该是自动化的、可审计的且易于理解。 官方文档 CD工作流(无ArgoCD) 假设有一个微服务应用程序…

Python解析和嵌入媒体资源的工具库之micawber使用详解

概要 在Web开发中,经常需要处理媒体资源的解析和嵌入,例如视频、音频、图片等。Python Micawber库就是一个用于解析和嵌入媒体资源的工具,它可以自动识别各种媒体资源的URL,并生成对应的嵌入代码,方便在网页中展示多媒体内容。 安装 可以通过pip来安装Micawber库: pip…

RustGUI学习(iced)之小部件(一):如何使用按钮和文本标签部件

前言 本专栏是学习Rust的GUI库iced的合集,将介绍iced涉及的各个小部件分别介绍,最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个,目前处于发展中(即版本可能会改变),本专栏基于版本0.12.1. 概述…

开源文本嵌入模型M3E

进入正文前,先扯点题外话 这两天遇到一个棘手的问题,在用 docker pull 拉取镜像时,会报错: x509: certificate has expired or is not yet valid 具体是下面👇这样的 rootDS918:/volume2/docker/xiaoya# docker pul…

数据中台工具的选型要点_光点科技

数据中台工具扮演着举足轻重的角色。想要全面理解数据中台工具的意义、作用以及应用方式,就必须深入探讨这一概念以及相关实践。 数据中台工具概述 数据中台,是一个支持数据集成、管理、分析和服务的平台,它能够帮助企业统一数据资源&#xf…

Linux使用操作(一)

Linux创建链接的方式 在Linux中,可以给文件创建链接。链接的意思可以理解是快捷方式,它指向另一个文件或目录。 软链接 软连接(也叫符号链接)是一种特殊类型的文件,它指向另一个文件或目录 语法 ln -s 原文件路径…

udp/tcp错误总结

udp tcp——多进程 tcp——多线程 tcp——线程池 tcp——守护进程 🎆udp  ✨pthread_create 错误总结  ✨LockGuard错误总结  ✨服务端需要写成多线程  ✨客户端也需要写成多线程  ✨多线程调试工具 🎆tcp  ✨tcp独有调试工具——telnet  ✨Threa…

【Unity】UnityEvent(一)

​UnityEvent----高效管理游戏事件的利器 在游戏开发中,事件系统是实现各种功能的关键组成部分。它允许我们将不同对象之间的交互解耦,使得代码更加模块化和易于维护。而UnityEvent作为Unity引擎提供的一种强大的事件系统工具,为开发者提供了…

CTFHub(web sql)(四)

Cookie注入 Cookie 注入的原理也和其他注入一样,只不过是将提交的参数已 Cookie 方式提交,而一般的注入是使用 GET 或者 POST 方式提交,GET 方式提交就是直接在网址后面加上需要注入的语句,POST 方式则是通过表单,GET …

数据仓库与数据挖掘(实验一2024.4.24)

实验准备: 1.下载conda 2.配置环境C:\ProgramData\miniconda3\Scripts 3.创建文件夹panda进入虚拟环境qq 激活虚拟环境:activate qq 启动jupyter lab(python语言环境编译):jupyter lab 4.panda下载 (…

【行为型模式】中介者模式

一、中介者模式概述 中介者模式定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式。(对象行为型模式) 中介者模式…

基于uni-app的动态表单

一、应用场景和意义 可以通过配置字段和校验规则,快速完成页面开发、提升开发效率 二、应用前提 形成ui/业务规范,最好是应用在问卷调查之类的业务 三、动态表单的功能 字段报错、快速滚动定位报错信息、支持字段值和字段规则拆分,便于实…

《R语言与农业数据统计分析及建模》学习——描述性统计分析

一、描述性统计概念和方法 1、概念和作用 描述性统计是对数据进行概括和描述,便于理解数据的特征、趋势和分布,帮助我们了解数据基本情况和总体特征,为后续更深入的数据分析和建模提供基础。 2、基础方法 (1)中心趋…

STM32的定时器

一、介绍 定时器的工作原理 通用定时器的介绍 定时器的计数模式 定时器时钟源 定时器溢出时间计算公式 二、使用定时器中断点亮LED灯 打开一个LED灯 更改TIME2 然后就是生成代码 三,代码

深度学习基础之《TensorFlow框架(15)—神经网络》

一、神经网络基础 1、什么是神经网络 人工神经网络(Artificial Neural Network,简写为ANN)。也简称为神经网络(NN) 是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)结构和功…

网络安全与密码学--AES加密

分组加密之AES加密算法 AES算法的诞生 python实现AES加密 AES加密详细流程 AES解密过程 AES的应用 1997年 NIST征集AES(Advanced Encryption Standard)2000年选中 https://www.nist.gov/ https://csrc.nist.gov/projects/block-cipher-techniques A…

WPForms Pro插件下载:简化您的在线表单构建,提升用户互动

在当今的数字化世界中,表单是网站与用户互动的关键。无论是收集信息、处理订单还是进行调查,一个好的表单可以极大地提升用户体验和转化率。WPForms Pro插件,作为一款专业的WordPress表单构建工具,旨在帮助您轻松创建美观、功能强…

如何求候选码、属性集的闭包

目录 一、基础理论 二、属性集的闭包 三、四类 四、例题 基础理论部分是我的异想天开,可跳过。 一、基础理论 数据库注重于研究关系,谈起关系,那么不得不提起《离散数学》,起初我认为求候选码的过程一定暗合《离散数学》中的…

【JavaScript】axios

基础使用 <script src"https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.min.js"></script> <script>axios.get(https://study.duyiedu.com/api/herolist).then(res> {console.log(res.data)}) </script>get - params <script s…

《智能前沿:应对ChatGPT算力挑战》

在全球人工智能热潮中&#xff0c;以 ChatGPT 为代表的 AIGC 技术引发了广泛关注。人工智能和机器学习等技术对数据规模及处理速度等提出了更高要求。在数据成为主要生产要素的当下和未来&#xff0c;如何跟上时代的发展步伐&#xff0c;构建适应 AI 需求的数据中心&#xff0c…