.NET管道应用——工作池
名词解释
工作池:一组等待任务分配的线程。一旦完成了所分配的任务,这些线程可继续等待任务的分配。
.NET管道:命名空间System.Threading.Channels中的Channel和Channel<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管道应用——工作池的更多相关文章
- [Go] golang无缓冲通道实现工作池控制并发
		展示如何使用无缓冲的通道创建一个goroutine池,控制并发频率1.无缓冲通道保证了两个goroutine之间的数据交换2.当所有的goroutine都忙的时候,能够及时通过通道告知调用者3.无缓冲 ... 
- Go基础系列:Go实现工作池的两种方式
		worker pool简介 worker pool其实就是线程池thread pool.对于go来说,直接使用的是goroutine而非线程,不过这里仍然以线程来解释线程池. 在线程池模型中,有2个队 ... 
- [Go]TCP服务中增加消息队列与工作池
		之前的处理中每一个连接都会创建一个主groutine , 每个连接中的主groutine中创建出读groutine 和写groutine 每个连接处理业务再单独开出一个groutine ,这样如果有1 ... 
- go语言从例子开始之Example33.工作池
		在这个例子中,我们将看到如何使用 Go 协程和通道实现一个工作池 . Example: package main import "fmt" import "time&qu ... 
- 003_对go语言中的工作池代码练习的一些思考和改进
		在进行工作池的代码练习时候,我发现了一个有趣的事情,首先看下面一段代码: package main import "fmt" import "time" fun ... 
- 034_go语言中的工作池
		代码演示 package main import "fmt" import "time" func worker(id int, jobs <-chan ... 
- [Golang]-8 工作池、速率限制、原子计数器、互斥锁
		目录 工作池 速率限制 原子计数器 互斥锁 工作池 在这个例子中,我们将看到如何使用 Go 协程和通道实现一个工作池 . func worker(id int, jobs <-chan int, ... 
- day 32 管道,信号量,进程池,线程的创建
		1.管道(了解) Pipe(): 在进程之间建立一条通道,并返回元组(conn1,conn2),其中conn1,conn2表示管道两端的连接对象,强调一点:必须在产生Process对象之前产生管道. ... 
- python摸爬滚打之day032 管道 数据共享 进程池
		1.进程池 当有成千上万个任务需要被执行的时候,有了进程池我们就不必去创建大量的进程. 首先,创建进程需要消耗时间,销毁进程(空间,变量,文件信息等等的内容)也需要消耗时间, 第二即便开启了成千上万的 ... 
随机推荐
- uniapp 滑动切换
			说明:本案例的样式基于colorui组件库 感兴趣的小伙伴可以看下教程 colorui组件库开发文档或者csdn的文档,顺便再分享下 colorui的群资源 最近项目中需要用到滑动切换的效果,自己懒得 ... 
- (转)linux下的系统调用函数到内核函数的追踪
			转载网址:http://blog.csdn.net/maochengtao/article/details/23598433 使用的 glibc : glibc-2.17使用的 linux kerne ... 
- 力扣832. 翻转图像-C语言实现-简单题
			题目 传送门 文本 给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果. 水平翻转图片就是将图片的每一行都进行翻转,即逆序.例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, ... 
- 用铁电存储器FRAM让穿戴式设备更省电
			可穿戴设备应用中的显示屏消耗了大部分电池电力.解决方法之一是直接提高电池容量,但是大容量电池会加大尺寸和重量,对可穿戴设备不合适,尤其是在市场不断追求更小型化的新款产品时更是如此.更具挑战性的是电池技 ... 
- Vue学习笔记-API调试工具--->国产apipost按装(比postman好按装好用)
			一 使用环境: windows 7 64位操作系统 二 Vue学习笔记-API调试工具--->apipost按装 1.下载: https://www.apipost.cn/ (比postm ... 
- 授权认证登录之 Cookie、Session、Token、JWT 详解
			一.先了解几个基础概念 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份. 互联网中的认证: 用户名密码登录 邮箱发送登录链接 手机号接收验证码 只要你能收到邮箱/验证码,就 ... 
- 第6章 for循环
			目标 掌握for循环的使用方法 理解for循环的嵌套 在第3章中,我们学习了times循环.times循环可以让一段代码重复执行指定的次数. 本章我们将学习另一种循环结构--for循环.它同样能让一段 ... 
- nignx的location正则匹配
			原文链接:http://nginx.org/en/docs/http/ngx_http_core_module.html Syntax: location [ = | ~ | ~* | ^~ ] ur ... 
- 记录安装freeswitch的日常
			已知安装版本:Linux:Centos7 Freeswitch:1.10.2 解: 注意:(最好呢是先下载好包,然后上传到这个所用的环境中) 1.安装对应依赖 yum install -y git a ... 
- 一文弄懂js的执行上下文与执行上下文栈
			目录 执行上下文与执行上下文栈 变量提升与函数提升 变量提升 函数提升 变量提升与函数提升的优先级 变量提升的一道题目引出var关键字与let关键字各自的特性 执行上下文 全局执行上下文 函数(局部) ... 
