iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > GO >golang基于errgroup实现并发调用的方法
  • 611
分享到

golang基于errgroup实现并发调用的方法

2024-04-02 19:04:59 611人浏览 泡泡鱼
摘要

目录串行调用基于sync.WaitGroup实现简单的并发调用基于errgroup.Group实现并发调用总结串行调用 在用Go编写WEB/rpc服务器的时候,经常会出现需要对下游多

串行调用

在用Go编写WEB/rpc服务器的时候,经常会出现需要对下游多 个/组 服务调用rpc(或者其他比较耗时的操作)的情况。
按照自然的写法,比如对下游有ABC三个调用,串行顺着写,就总共要花费TimeA+TimeB+TimeC的时间:

func Handler(ctx context.Context) {
    var a, b, c respType
    a = A(ctx)
    b = B(ctx)
    c = C(ctx)
}

基于sync.WaitGroup实现简单的并发调用

但经常地,几个rpc相互之间没有依赖关系的情况,这时,我们稍加思考就会想到使用并发的方式,同时发出请求,阻塞等到所有请求返回,这样,总体耗时就变成了Max(TimeA, TimeB, TimeC),我们可以通过常用的sync.WaitGroup轻松实现这事:

func Handler(ctx context.Context) {
    var a, b, c respType
   	wg := sync.WaitGroup{}
	wg.Add(3)
	go func() {
		defer wg.Done()
		a = A(ctx)
	}()
	go func() {
		defer wg.Done()
		b = B(ctx)
	}()
	go func() {
		defer wg.Done()
		c = C(ctx)
	}()
	wg.Wait()
}

但是现实事件是不完美的,尤其是在加入了网络这一因素后,我们经常会需要处理调用失败的情况,很多情况下,并发的几个操作只要任一失败,整个处理就算失败了,但是由于WaitGroup要等所有调用都done才能返回,因此调用时间是由耗时最长的那个(不一定是失败的)决定的,如果不是失败的那个,其实就产生了资源浪费,如下图,B最先失败了,此时逻辑上已经可以返回,但是实际却等到了最长的调用-A返回了整个函数才返回:

func Handler(ctx context.Context) {
    var a, b, c respType
    var errA, errB, errC error
   	wg := sync.WaitGroup{}
	wg.Add(3)
	go func() {
		defer wg.Done()
		a, errA = A(ctx)
	}()
	go func() {
		defer wg.Done()
		b, errB = B(ctx)
	}()
	go func() {
		defer wg.Done()
		c, errC = C(ctx)
	}()
	wg.Wait()
	if errA != nil {
	// ...
	}
	if errB != nil {
	// ...
	}
	if errC != nil {
	// ...
	}
}

基于errgroup.Group实现并发调用

这对于追求极致的我们来说显然是不能接受的,我们希望达到,如果有任意一个调用报错,立刻让所有调用返回的效果:

好在,我们有现成的工具可以用,通过引入"golang.org/x/sync/errgroup",可以轻松实现上面的目的。

为了使用errgroup,先使用WithContext方法创建一个Group

wg, groupCtx := errgroup.WithContext(ctx)

返回的第一个参数是*errgroup.Group,第二个则是在子调用中应该使用的context。

然后,使用Go方法调用所有的并发方法

	wg.Go(func() error {
		var err error
		a, err = A(groupCtx)
		return err
	})

最后, 使用Wait方法等待并发结束,返回值是所有子调用中第一个非nil的error,全成功的话就是nil。

if err := wg.Wait(); err != nil {
// ...
}

因此整体,我们的代码差不多就长这个样子

func handler(ctx context.Context) {
    var a, b, c respType
    wg, groupCtx := errgroup.WithContext(ctx)
	wg.Go(func() error {
		var err error
		a, err = A(groupCtx)
		return err
	})
	wg.Go(func() error {
		var err error
		b, err = B(groupCtx)
		return err
	})
	wg.Go(func() error {
		var err error
		c, err = C(groupCtx)
		return err
	})
	if err := wg.Wait(); err != nil {
    // ... 错误处理
    }
    // 全部成功
}

errgroup内部通过封装了waitGroup和sync.Once实现了这个语法糖。

使用时特别要注意的是,errgroup的提前取消调用rpc是通过cancel那个返回的context(即上面的groupCtx)实现的,因此在所有子调用中都要实现监听groupCtx的Done事件。而在正常的rpc框架中都已经帮我们实现了这件事,因此我们只要保证传进去的是groupCtx即可。

总结

errgroup帮我们封装了并发调用下游时快速失败的逻辑,我们能很方便地使用它进行业务代码的编写。使用的关键是一定要记得在子调用中传递WithContext中返回的Context。

好用的工具千千万,让我们一个个来掌握!

您可能感兴趣的文档:

--结束END--

本文标题: golang基于errgroup实现并发调用的方法

本文链接: https://www.lsjlt.com/news/121165.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • golang基于errgroup实现并发调用的方法
    目录串行调用基于sync.WaitGroup实现简单的并发调用基于errgroup.Group实现并发调用总结串行调用 在用go编写web/rpc服务器的时候,经常会出现需要对下游多...
    99+
    2024-04-02
  • 基于Golang 高并发问题的解决方案
    Golang 高并发问题的解决 Golang在高并发问题上,由于协程的使用,相对于其他编程语言,已经有了很大的优势,即相同的配置上,Golang可以以更低的代价处理更多的线程,同样的...
    99+
    2024-04-02
  • Golang基于泛化调用与Nacos实现Dubbo代理的方法是什么
    这篇“Golang基于泛化调用与Nacos实现Dubbo代理的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Gol...
    99+
    2023-07-05
  • 基于JS实现带并发限制的异步调度器
    题目描述 JS实现一个带并发限制的异步调度器scheduler,保证同时运行的任务最多有两个。 例如目前有4个任务,完成时间分别为,1000ms,500ms,300ms,400ms ...
    99+
    2023-05-20
    JS实现异步调度器 JS异步调度器 JS调度器
  • golang函数实现并发编程的方法
    go 语言函数通过创建协程和利用通道实现了并发编程。协程是轻量级线程,通过 go 关键字创建。通道是协程间传递数据的管道,生产者协程使用 操作符接收数据。以下示例演示了并行处理数据的实...
    99+
    2024-04-25
    golang 并发
  • python基于并发与socket实现远
    FTP程序 Client: * bin/start.py 程序入口 * conf/配置文件存放 * core/ * auth.py 登陆,注册以及上传下载查看当前文件夹下文件以及删除功能存放 * cline.py 与服务端...
    99+
    2023-01-30
    python socket
  • Golang基于泛化调用与Nacos实现Dubbo代理
    目录前言准备实现项目结构go.mod返回数据格式获取 nacos 元信息泛化调用提供 http 服务启动效果前言 由于工作中使用的 rpc 框架是 dubbo,经常需要调试不同环境的...
    99+
    2023-05-14
    Golang实现Dubbo代理 Golang Dubbo代理 Golang Dubbo
  • Golang并发调度器:Go WaitGroup的优化实现
    在Golang中,可以使用`sync.WaitGroup`来实现并发调度器。`WaitGroup`提供了一种简单的方式来等待一组并发...
    99+
    2023-10-08
    Golang
  • Golang函数的并发调用实践分享
    作为一门高效、轻量、并发支持良好的编程语言,Golang 的函数并发调用是一项很重要的特性。在这篇文章中,本文将分享一些关于 Golang 函数并发调用的实践经验,希望能对 Golang 开发者有所帮助。一、Goroutine 的使用Gor...
    99+
    2023-05-18
    Golang 并发调用 实践分享
  • Golang函数的递归调用实现方法
    Golang函数的递归调用实现方法随着Golang在软件开发中的广泛应用,函数的递归调用成为了程序员们实现复杂逻辑和算法的重要手段。递归调用是指在函数内部不断地调用自身,直至满足某一个条件终止循环。在本文中,我们将探讨Golang函数的递归...
    99+
    2023-05-17
    函数 Golang 递归调用
  • 基于Feign实现异步调用
    目录一、背景二、使用feign理由三、解决方案四、demo代码实现4.1 接口编写4.2 接口发布4.3 调用4.4 结果(很明显,是异步调用) 五、问题一、背景 希望将h...
    99+
    2024-04-02
  • 基于redis乐观锁实现并发排队
    有个需求场景是这样的,使用Redis控制scrapy运行的数量。当系统的后台设置为4时,只允许scapry启动4个任务,多余的任务则进行排队。 概况 最近做了一个django + scrapy + celery + re...
    99+
    2022-12-25
    redis队列实现高并发 redis消息队列实现高并发 redis乐观锁实现高并发
  • 基于Scala和Java方法的相互调用
    目录在Java中调用Scala的方法呢?1.首先是静态方法2. JAVA中调用Scala的方法3.Scala中的非静态方法4.Java中的调用scala中调用java方法报错在Sca...
    99+
    2024-04-02
  • C++并发编程:如何实现基于事件驱动的并发模型?
    基于事件驱动的并发模型是 c++++ 中一种流行的并发编程范式,它使用事件循环处理来自不同来源的事件。事件循环是一个无限循环,检索和处理事件队列中的事件,通常通过调用回调函数。在 c++...
    99+
    2024-05-06
    c++ 并发编程
  • Golang并发编程:使用Go WaitGroup实现任务调度器
    任务调度器是一种常见的并发编程模式,它用于同时执行多个任务并等待所有任务完成后再继续执行其他操作。在Golang中,可以使用sync...
    99+
    2023-10-20
    Golang
  • 关于golang高并发的实现与注意事项说明
    一、并发的意义 并发的意义就是让 一个程序同时做多件事情,其目的只是为了能让程序同时做另一件事情而已,而不是为了让程序运行的更快(如果是多核处理器,而且任务可以分成相互独立的部分,那...
    99+
    2024-04-02
  • 基于Java实现Socket编程的方法
    这篇文章主要介绍“基于Java实现Socket编程的方法”,在日常操作中,相信很多人在基于Java实现Socket编程的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”基于Java实现Socket编程的方法...
    99+
    2023-06-29
  • 基于redis乐观锁怎么实现并发排队
    这篇“基于redis乐观锁怎么实现并发排队”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“基于redis乐观锁怎么实现并发排队...
    99+
    2023-07-04
  • 实现高性能的Select Channels Go并发式编程的golang方法
    要实现高性能的Select Channels Go并发式编程的golang方法,可以按照以下步骤进行:1. 定义所需的通道和数据结构...
    99+
    2023-10-20
    Golang
  • C++基于reactor的服务器百万并发如何实现
    这篇文章主要介绍“C++基于reactor的服务器百万并发如何实现”,在日常操作中,相信很多人在C++基于reactor的服务器百万并发如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++基于reac...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作