名词解释

工作池:一组等待任务分配的线程。一旦完成了所分配的任务,这些线程可继续等待任务的分配。

.NET管道:命名空间System.Threading.Channels中的ChannelChannel<T>对象,看nuget包,最低支持 .NETStandard 1.3

动机

最近在挑选.NET5项目动态编译运行字符串方案,最后选定了两个脚本语言库,想要测试一下高并发下的效率如何,就有了自己写个工作池来测试的念头。

Talk is cheap, show me the code.

/// <summary>
/// 工作池
/// </summary>
/// <param name="work">具体工作</param>
/// <param name="workerCount">工人数</param>
/// <param name="count">工作总件数</param>
static async ValueTask WorkerPool<T>(Func<int, int, Task<T>> work, int workerCount, int count)
{
Channel<T> results = Channel.CreateUnbounded<T>(); //用于收集结果的不限容管道
Channel<int> workers = Channel.CreateBounded<int>(workerCount); //用于安排工作的限容管道,容量 = 工人数量(workerCount)
var _ = ProcessResult(); //先开启收集结果的线程 var _ = 的作用在于 disable 4014警告
await ArrangeWork(); //等待安排工作并完成 async ValueTask ProcessResult() //处理结果
{
for (var i = 0; i < count; i++) //读取结果次数 = 工作总件数
await results.Reader.ReadAsync(); //从结果管道读取结果,可以按照具体需求扩展
results.Writer.Complete(); // 先结束收集结果的管道
workers.Writer.Complete(); // 再结束安排工作的管道
} async ValueTask ArrangeWork() //安排工作
{
var __ = Enumerable.Range(0, workerCount).Select(DoWork).ToArray(); //初始化工人
for (var i = 0; i < count; i++)
await workers.Writer.WriteAsync(i); //
await workers.Reader.Completion; //等待安排工作的管道完结。注:如果不等待,最后一批任务没有结束就返回了。
} async ValueTask DoWork(int workerId) //去工作
{
await foreach (var order in workers.Reader.ReadAllAsync()) //应用异步Stream接取工作
{
var rst = await work(workerId, order); //调用具体工作
await results.Writer.WriteAsync(rst); //写入工作成果到收集结果的管道
}
}
}
static async ValueTask ChannelTest()
{
var sw = new Stopwatch();
sw.Start();
await WorkerPool(async (workerId, order) =>
{
await Task.Delay(1000);
WriteLine($"{sw.Elapsed:ss\\.fff}: {order}");
return true;
}, 3, 9); //3个工人 9工作量
WriteLine($"{sw.Elapsed:ss\\.fff}: end");
}

逻辑不难,不过一开始没想到用两个管道,卡了很久,后来观摩了一下B站某光头大佬的goroutine 池并发版 TCP 端口扫描器的源码,才写出来。

上述ChannelTest运行结果:

01.034: 0
01.034: 2
01.034: 1
02.049: 3
02.049: 4
02.049: 5
03.065: 8
03.065: 7
03.065: 6
03.074: end

可以看到,3个工人分配了9工作量,总计需要3秒完成任务。

.NET管道应用——工作池的更多相关文章

  1. [Go] golang无缓冲通道实现工作池控制并发

    展示如何使用无缓冲的通道创建一个goroutine池,控制并发频率1.无缓冲通道保证了两个goroutine之间的数据交换2.当所有的goroutine都忙的时候,能够及时通过通道告知调用者3.无缓冲 ...

  2. Go基础系列:Go实现工作池的两种方式

    worker pool简介 worker pool其实就是线程池thread pool.对于go来说,直接使用的是goroutine而非线程,不过这里仍然以线程来解释线程池. 在线程池模型中,有2个队 ...

  3. [Go]TCP服务中增加消息队列与工作池

    之前的处理中每一个连接都会创建一个主groutine , 每个连接中的主groutine中创建出读groutine 和写groutine 每个连接处理业务再单独开出一个groutine ,这样如果有1 ...

  4. go语言从例子开始之Example33.工作池

    在这个例子中,我们将看到如何使用 Go 协程和通道实现一个工作池 . Example: package main import "fmt" import "time&qu ...

  5. 003_对go语言中的工作池代码练习的一些思考和改进

    在进行工作池的代码练习时候,我发现了一个有趣的事情,首先看下面一段代码: package main import "fmt" import "time" fun ...

  6. 034_go语言中的工作池

    代码演示 package main import "fmt" import "time" func worker(id int, jobs <-chan ...

  7. [Golang]-8 工作池、速率限制、原子计数器、互斥锁

    目录 工作池 速率限制 原子计数器 互斥锁 工作池 在这个例子中,我们将看到如何使用 Go 协程和通道实现一个工作池 . func worker(id int, jobs <-chan int, ...

  8. day 32 管道,信号量,进程池,线程的创建

    1.管道(了解) Pipe(): 在进程之间建立一条通道,并返回元组(conn1,conn2),其中conn1,conn2表示管道两端的连接对象,强调一点:必须在产生Process对象之前产生管道. ...

  9. python摸爬滚打之day032 管道 数据共享 进程池

    1.进程池 当有成千上万个任务需要被执行的时候,有了进程池我们就不必去创建大量的进程. 首先,创建进程需要消耗时间,销毁进程(空间,变量,文件信息等等的内容)也需要消耗时间, 第二即便开启了成千上万的 ...

随机推荐

  1. 12月15日BGV币行情分析

    今日,DeFi市场格外精彩.各主流概念币种走势出现了涨跌各半的两极态势.笔者认为,由于并没有总体可以利好DeFi市场的基本面因素,所以各DeFi概念币种的涨跌态势,还是与各自的基本面和技术面走势相关. ...

  2. C++算法代码——卡片游戏

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?cid=1397&pid=2 题目描述 桌上有一叠牌,从第一张牌(即位于顶面的牌)开始 ...

  3. .NET Core Swagger 的分组使, 以及相同Action能被多个分组公用,同时加载出尚未分组的数据出来

    1.本文章参考 点击链接跳转 改写的 一对多分组模式.需要一对一的可以参考 2.本文主要讲的是 一对多 分组公用, 同时把尚未分组的加载出来 3.效果演示GIF图: 具体操作代码如下: 1.在项目创建 ...

  4. VMware vSphere 虚拟化平台的安装及使用

    首先解释一下这些名词, vSphere是什么? vSphere 是VMware公司发布的一整套产品包,是VMware公司推出的一套服务器虚拟化解决方案,包含VMware ESXi hypervisor ...

  5. 翻译:《实用的Python编程》02_06_List_comprehension

    目录 | 上一节 (2.5 collections模块) | 下一节 (2.7 对象模型) 2.6 列表推导式 一个常见的任务是处理列表中的项(译注:元素).本节介绍列表推导式,完成此任务的强大工具. ...

  6. 适配三星Galaxy S8及S8+ 屏幕比例为 18.5:9

    开发者只需在App的AndroidManifest.xml文件<application> </application>中添加如下代码: <meta-data androi ...

  7. Pyqt5——变色的表格

    需求:鼠标左键点击表格后,对应的单元格背景颜色发生变化. 实现:(1)使用Qt的model-view模式生成表格视图. (2)重写表格的点击事件. (3)设置表格的背景颜色. 正常情况下,当用户选中单 ...

  8. ElasticSearch学习笔记(超详细)

    文章目录 初识ElasticSearch 什么是ElasticSearch ElasticSearch特点 ElasticSearch用途 ElasticSearch底层实现 ElasticSearc ...

  9. git仓库创建及基本使用

    创建git用户 useradd git passwd git 创建目录 mkdir /home/git/repos/app.git/ -p 初始化目录 cd /home/git/repos/app.g ...

  10. dubbo实战之二:与SpringBoot集成

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...