Go Sync并发包之errgroup

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

想想看,你有一个函数可以做 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{}// 将限制设置为2g.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 errorif err := g.Wait(); err != nil {fmt.Printf("Encountered an error: %v\n", err)}
}

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

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

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

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

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

相关文章

BRC铭文NFT铸造质押挖矿系统开发运营

区块链技术的不断演进与应用拓展,为数字资产领域带来了更多可能性。BRC铭文NFT铸造质押挖矿系统的开发与运营,将为用户提供一种全新的数字资产体验,下文将介绍其版/需求方案/逻辑项目。 1. 系统概述 BRC铭文NFT铸造质押挖矿系统旨在结合区块…

数据库之数据库恢复技术思维导图+大纲笔记

大纲笔记: 事务的基本概念 事务 定义 用户定义的一个数据库操作系列,这些操作要么全做,要么全不做,是一个不可分割的基本单位 语句 BEGIN TRANSACTION 开始 COMMIT 提交,提交事务的所有操作 ROLLBACK 回滚&#xff0c…

电商技术揭秘三十一:智能风控与反欺诈技术

相关系列文章 电商技术揭秘相关系列文章合集(1) 电商技术揭秘相关系列文章合集(2) 电商技术揭秘二十八:安全与合规性保障 电商技术揭秘二十九:电商法律合规浅析 电商技术揭秘三十:知识产权保…

科林Linux_3 进程

一、进程基础 操作系统基础的执行单元,调度单位 静态数据:只占用磁盘空间,不消耗其他资源 动态数据:磁盘 内存 CPU 1. 编译器将源码编译成一个可执行文件.exe/.elf 2. 运行后系统生成一个同名的进程 程序是进程的静态表现&a…

网络变压器的磁芯在使用中起着至关重要的作用

网络变压器的磁芯在使用中起着至关重要的作用。它主要有以下几个功能: 1. **提供磁通路径**:磁芯为变压器中电磁感应提供了闭合的磁通路径。这有助于提高变压器的效率,因为它确保了磁场能够有效地通过绕组。 2. **减少能量损失**&#xff1…

开发环境中的调试视图(IDEA)

当程序员写完一个代码时必然要运行这个代码,但是一个没有异常的代码却未必满足我们的要求,因此就要求程序员对已经写好的代码进行调试操作。在之前,如果我们要看某一个程序是否满足我们的需求,一般情况下会对程序运行的结果进行打…

Spring框架九大核心功能全面揭秘(一)

目录 资源管理 Java资源管理 1、来个Demo 2、原理 Spring资源管理 1、资源抽象 Resource WritableResource 2、资源加载 3、小结 环境 1、Environment 2、配置属性源PropertySource 3、SpringBoot是如何解析配置文件 类型转换 1、类型转换API …

Ubuntu+Systemd服务+实现开机自启

1.创建一个新的 systemd 服务文件 现在随便一个地方创建txt文档 如果想要启动sh脚本,就把下面的代码输入到txt文档中 [Unit] DescriptionRun Python script on specific executable run Afternetwork.target[Service] Typesimple ExecStart/home/tech/run_on_exe…

光接入网络的超宽带半导体光放大器

添加图片注释,不超过 140 字(可选) 新颖的双有源层结构获得宽增益光谱,应用于多波单纤双向光放大 ----翻译Xiao Sun等人2016年撰写的文章,文中给出了宽光谱SOA的一种新颖的结构设计方法和仿真结果,但并未给…

社交媒体数据恢复:Instagram

Instagram数据恢复方法 在本文中,我们将详细介绍如何恢复在Instagram上删除的照片、消息和其他数据。请注意,这些方法可能适用于其他类型的社交媒体数据,但具体效果取决于数据的实际状态和存储设备的健康状况。 一、准备工作 在开始数据恢…

四川赢涟电子商务有限公司深耕抖音电商服务

在当今数字化、网络化高速发展的时代,电子商务行业异军突起,成为推动经济增长的重要力量。四川赢涟电子商务有限公司凭借其敏锐的市场洞察力和创新精神,专注于抖音电商服务,致力于为广大消费者提供便捷、高效、个性化的购物体验&a…

kafka启动报错(kafka.common.InconsistentClusterIdException)

文章目录 前言kafka启动报错(kafka.common.InconsistentClusterIdException)1. 查找日志2. 定位问题/解决 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不…

基于YOLOv8+Pyqt5火焰烟雾检测系统

1、YOLOv8的基本原理 YOLOv8是一种前沿的目标检测技术,它基于先前YOLO版本在目标检测任务上的成功,进一步提升了性能和灵活性。主要的创新点包括一个新的骨干网络、一个新的 Ancher-Free 检测头和一个新的损失函数,可以在从 CPU 到 GPU 的各…

Golang | Leetcode Golang题解之第47题全排列II

题目: 题解: func permuteUnique(nums []int) (ans [][]int) {sort.Ints(nums)n : len(nums)perm : []int{}vis : make([]bool, n)var backtrack func(int)backtrack func(idx int) {if idx n {ans append(ans, append([]int(nil), perm...))return}…

数据分析学习资源(未完)

1、PDF 数据分析自学攻略 增长黑客(AARRR) 量化思维

glib读写ini文件测试

函数简介 g_key_file_load_from_file g_key_file_load_from_file() 是 GLib 库中的一个函数,用于从指定的文件路径加载一个键值对文件(通常是一个 .ini 风格的配置文件)。这个函数是 GKeyFile 结构体相关API的一部分,GKeyFile 用…

C++面向对象程序设计 - 重载运算符进一步讨论

函数重载就是对一个已有的函数赋予新的含义,使之实现新的功能。因此一个函数名就可以用来代表不同功能的函数,也就是一名多用。运算符也可以重载,即运算符重载(operator overloading)。 一、非成员、非友元的重载运算…

STM32F103学习笔记 | 1.Keil5详细安装教程

Keil5详细安装教程 https://www.keil.com/download/product/

使用API有效率地管理Dynadot域名,自查账户信息

关于Dynadot Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮…

大型组织企业 怎么实现便捷高效的跨地区文件交换?

大型组织企业,尤其是银行、邮政、大型集团、跨国企业等,都会存在多个分支机构,会面临跨地区文件交换的场景和需求。 跨地区文件交换可能会遇到以下问题: 1、网络带宽限制:跨国或跨大陆传输时,网络带宽可能…