- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Golang并发编程包之 Errgroup由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
四哥水平有限,如果有翻译或理解错误的点,烦请帮忙指出,感谢.
这是系列文章的第二篇,第一篇文章点击这里查看.
原文如下:
基于 goroutine 和 channel 的并发特性,使得 Go 成为了强大的并发语言。上一篇文章,我们讨论了如何构建 workerPool 来提高程序的并发性能,换句话说,避免耗尽系统资源。但那只是一个简单的示例,演示我们应该如何实现.
基于对上一篇文章的学习,在这篇文章里面,我们将构建一个健壮的解决方案,以便在任何其他应用程序里面可以使用该方案。网络上有其他复杂架构的解决方案,比如使用调度器等等。实际上,我们并不需要这些复杂的设计,仅仅使用一个共享 channel 就可以解决问题。我们一起来看下,该如何构建呢?
代码结构 。
我们创建了一个通用的 workerPool 包,根据业务所需的并发性使用 worker 来处理任务。一起来看下目录结构:
workerpool 目录在项目的根目录下。Task 是需要处理单个工作单元;Worker 是一个简单的 worker 函数,用于执行任务;而 Pool 用于创建、管理 workers.
实现 。
先看下 Task 代码:
Task 是一个简单的结构体,保存处理任务所需要的一切数据。创建 task 时,传递了 Data 和待执行函数 f,process() 函数会处理任务。处理任务时,将 Data 作为参数传递给函数 f,并将执行结果保存在 Task.Err 里.
我们来看下 Worker 是如何处理任务的:
我们创建了一个小巧的 Worker 结构体,包含 worker ID 和 一个保存待处理任务的 channel。在 Start() 方法里,使用 for range 从 taskChan 读取任务并处理。可以想象的到,多个 worker 可以并发地执行任务.
workerPool 。
我们通过实现 Task 和 Worker 来处理任务,但是好像还缺点什么东西,谁负责生成这些 worker 并将任务发送给它们?答案是:Worker Pool.
上面的代码,pool 保存了所有待处理的任务,并且生成与 concurrency 数量一致的 goroutine,用于并发地处理任务。workers 之间共享缓存 channel -- collector.
所以,当我们把这个工作池跑起来时,可以生成满足所需数量的 worker,workers 之间共享 collector channel。接着,使用 for range 读取 tasks,并将读取到的 task 写入 collector 里。我们使用 sync.WaitGroup 实现协程之间的同步。现在我们有了一个很好的解决方案,一起来测试下.
上面的代码,创建了 100 个任务并且使用 5 个并发处理这些任务.
输出如下:
处理 100 个任务花费了 2s,如何我们将并发数提高到 10,我们会看到处理完所有任务只需要大约 1s.
我们通过实现 workerPool 构建了一个健壮的解决方案,具有并发性、错误处理、数据处理等功能。这是个通用的包,不耦合具体的实现。我们可以使用它来解决一些大问题.
进一步扩展:后台处理任务 。
实际上,我们还可以进一步扩展上面的解决方案,以便 worker 可以在后台等待我们投递新的任务并处理。为此,代码需要做一些修改,Task 结构体保持不变,但是需要小改下 Worker,看下面代码:
Worker 结构体新加 quit channel,并且新加了两个方法。StartBackgorund() 在 for 循环里使用 select-case 从 taskChan 队列读取任务并处理,如果从 quit 读取到结束信号就立即返回。Stop() 方法负责往 quit 写入结束信号.
添加完这两个新的方法之后,我们来修改下 Pool:
Pool 结构体添加了两个成员:Workers 和 runBackground,Workers 保存所有的 worker,runBackground 用于维持 pool 存活状态.
添加了三个新的方法,AddTask() 方法用于往 collector 添加任务;RunBackground() 方法衍生出一个无限运行的 goroutine,以便 pool 维持存活状态,因为 runBackground 信道是空,读取空的 channel 会阻塞,所以 pool 能维持运行状态。接着,在协程里面启动 worker;Stop() 方法用于停止 worker,并且给 runBackground 发送停止信号以便结束 RunBackground() 方法.
我们来看下具体是如何工作的.
如果是在现实的业务场景中,pool 将会与 HTTP 服务器一块运行并消耗任务。我们通过 for 无限循环模拟这种这种场景,如果满足某一条件,pool 将会停止.
当执行上面的代码时,我们就会看到有随机的 task 被投递到后台运行的 workers,其中某一个 worker 会读取到任务并完成处理。当满足某一条件时,程序便会停止退出.
总结 。
基于上一篇文章的初步解决方案,这篇文章讨论了通过 workPool 构建一个强大的解决方案。同时,我们进一步扩展了该方案,实现后台运行 pool 并处理投递的任务.
点击【阅读原文】直达代码仓库[1].
参考资料 。
[1]代码仓库: https://github.com/Joker666/goworkerpool 。
via:https://hackernoon.com/concurrency-in-golang-and-workerpool-part-2-l3w31q7 。
作者:Hasan 。
原文链接:https://mp.weixin.qq.com/s/NcrENqRyK9dYrOBBI0SGkA 。
最后此篇关于Golang并发编程包之 Errgroup的文章就讲到这里了,如果你想了解更多关于Golang并发编程包之 Errgroup的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试在多线程环境中实现某种累积逻辑;我想知道没有 lock 和 synchronized 关键字是否有更好/更快的方法来做到这一点?以下是我当前的代码: public class Concurr
我需要帮助构建一个实现信号量的监视器,简单的 C 示例就可以。 这是为了证明可以在任何可以使用信号量的地方使用监视器。 最佳答案 如果您说允许使用互斥锁/condvars,请检查: #include
我已经构建了一些返回部分产品目录的 ajax,并且我正在尝试将 xml 输出到文档中,到目前为止,这是我所拥有的: $("#catalog").append("Item NamePriceDe
很抱歉,如果我的问题之前已经被问过,或者它太明显了,但我真的需要澄清这一点。感谢您的帮助。 在多用户界面中,如果来自不同用户的相同事务同时到达服务器,会发生什么? 我有下一张表: create tab
这可能是一个愚蠢的问题,但是这个程序的输出(它的方式)可以为零吗? public class Test2{ int a = 0; AtomicInteger b = new Atomi
假设我本地主机上的一个网站处理每个请求大约需要 3 秒。这很好,正如预期的那样(因为它在幕后进行了一些奇特的网络)。 但是,如果我在选项卡(在 firefox 中)中打开相同的 url,然后同时重新加
我对 MongoDB 的读锁定有点困惑。单个集合可以支持多少个并发读取操作? 最佳答案 如 tk 给出的链接中所写:http://www.mongodb.org/pages/viewpage.acti
如果有四个并发的 CUDA 应用程序在一个 GPU 中竞争资源会发生什么这样他们就可以将工作卸载到图形卡上了? Cuda Programming Guide 3.1 提到那里 某些方法是异步的: 内核
👊上次的百度面试遇到了关于spark的并发数的问题,今天我们就来将这些问题都一并解决一下,图画的的有点丑,还行大家见谅,百度实习的问题我放在了下面的链接👇: 链接: 2022百度大数据开发工程师实
我对 Groovy 线程有疑问。 我的任务是以某种方式翻译给定目录中的每个文件 并将生成的输出放在其他目录中的文件中。 我编写了以下代码,该代码有效: static def translateDir(
Java中的同步和锁定有什么区别? 最佳答案 synchronized是语言关键字;锁是对象。 当一个方法或代码块被标记为同步时,您是说该方法或代码块必须先获得某个锁对象(可以在同步的语法中指定)才能
我需要创建一个能够同时处理来自客户端的多个请求的并发 RPC 服务器。 使用 rpcgen linux编译器(基于sun RPC),不支持-A为并发服务器创建 stub 的选项。 (-A 选项在 so
System.out.println("Enter the number of what you would like to do"); System.out.println("1 = Manuall
我正在将我的应用程序移植到 iOS 8.0 并注意到 UIAlertView 已被弃用。 所以我改变了使用 UIAlertController 的方法。这在大多数情况下都有效。 除了,当我的应用程序打
我正在逐行同时读取两个文本文件。 我特别想做的是当lineCount在每个线程上都是相同的我想看看扫描仪当前正在读取的字符串。 我环顾四周寻找可以实现的某些模式,例如 Compare and Swap
我正在阅读 Java Concurrency in Practice .在章节中断政策部分 取消和关闭 它提到 A task should not assume anything about the
我正在尝试学习线程,互斥等的基础知识。遵循here的文档和示例。在下面的代码中,我得到预期的输出。问题: 想确认我是否有任何陷阱?我们如何改善下面的代码? 我的线程在哪一行尝试获取互斥锁或正在等待互斥
并发是指两个任务在不同的线程上并行运行。但是,异步方法并行运行,但在同一个线程上。这是如何实现的?另外,并行性怎么样? 这三个概念有什么区别? 最佳答案 并发和并行实际上与您正确推测的原理相同,两者都
以此ConcurrentDouble类定义为例: public class ConcurrentDouble { public double num = 0; public void subt
在得知并发确实增加了许多人的吞吐量后,我一直计划在项目中使用并发。现在我在多线程或并发方面还没有做太多工作,因此决定在实际项目中使用它之前学习并进行简单的概念验证。 以下是我尝试过的两个示例: 1.
我是一名优秀的程序员,十分优秀!