首页 > 编程语言 >C# 一个自己写的异步并行执行器

C# 一个自己写的异步并行执行器

时间:2024-07-17 12:11:33浏览次数:13  
标签:异步 Task C# 并行执行 token output parallelCount

有的时候咱们需要循环执行业务,如果单以处理过程不是计算密集型,就可以使用多线程并行处理,这样能大幅度提高执行效率

最开始我是想着有没有现成的,结果找了半天没发现有现成的,于是就自己封装了一个,简单测试了一下发现没啥问题

异步并行执行器

    /// <summary>
    /// 异步并行执行器,可以将任务并行执行,提高执行速度
    /// </summary>
    public class AsyncParallelExecutor<T> {
        /// <summary>
        /// 执行过程
        /// </summary>
        /// <param name="progressInfo">进度信息</param> 
        /// <param name="arg">参数数据</param>
        /// <returns>异步执行的任务</returns>
        public delegate Task ProcessDelegate(string progressInfo, T arg);
        /// <summary>
        /// 执行的任务总数量
        /// </summary>
        readonly int _totalCount;
        readonly object _lock = new object();
        readonly Queue<T> queue = new Queue<T>();
        readonly int _parallelCount;
        readonly ProcessDelegate _process;
        readonly CancellationToken _token;
        readonly Action<string, Exception> _output;
        /// <summary>
        /// 创建一个异步并行执行器
        /// </summary>
        /// <param name="args">任务的参数集合</param>
        /// <param name="process">对数据进行处理的过程</param>
        /// <param name="token">取消令牌</param>
        /// <param name="output">信息输出</param>
        /// <param name="parallelCount">执行的异步数量</param>
        public AsyncParallelExecutor(IEnumerable<T> args, ProcessDelegate process, CancellationToken token, Action<string, Exception> output, int parallelCount = 2) {
            foreach (var arg in args) {
                queue.Enqueue(arg);
            }
            _totalCount = queue.Count;
            _process = process;
            _token = token;
            _output = output;
            if (_output == null) {
                _output = (str, ex) => { };
            }
            _parallelCount = parallelCount;
            _output($"共{_totalCount}个任务,将使用{_parallelCount}个异步任务并行处理", null);
        }
        /// <summary>
        /// 开始执行异步并行任务
        /// </summary>
        public async Task Start() {
            Task[] tasks = new Task[_parallelCount];
            for (int i = 0; i < _parallelCount; i++) {
                tasks[i] = AsyncTask(i);
            }
            await Task.WhenAll(tasks);
        }
        /// <summary>
        /// 异步函数,不会阻塞
        /// </summary>
        Task AsyncTask(int progressID) {
            return Task.Run(async () => {
                while (true) {
                    _token.ThrowIfCancellationRequested();
                    try {
                        var (success, index) = TryGet(out T val);
                        if (success == false) {
                            break;
                        }
                        await _process($"进程{progressID},进度{index}/{_totalCount}", val);
                    } catch (OperationCanceledException) {
                        _token.ThrowIfCancellationRequested();
                    } catch (Exception ex) {
                        _output(null, ex);
                    }
                }
                _output($"进程{progressID} 结束", null);
            });
        }
        (bool success, int index) TryGet(out T val) {
            lock (_lock) {
                if (queue.Count > 0) {
                    val = queue.Dequeue();
                    return (true, _totalCount - queue.Count);
                } else {
                    val = default;
                    return (false, _totalCount);
                }
            }
        }
    }
View Code

使用方法

        async Task Test11() {
            CancellationToken token = new CancellationTokenSource().Token;
            List<string> taskData = new List<string>();  //将任务封装成泛型集合
            for (int i = 0; i < 10; i++) {
                taskData.Add(Guid.NewGuid().ToString()); //模拟任务数据
            }
            //并行启动5个异步线程并行执行任务,原本需要10*3=30秒的时间,现在只需要30/5=6秒
            var ape = new AsyncParallelExecutor<string>(taskData, Execute, token, Output, 5);
            Log.Info("开始执行...");
            try {
                await ape.Start();
            } catch (OperationCanceledException) {
                Log.Info("任务被中途取消");
            }
            Log.Info("全部执行完毕");
        }
        /// <summary>
        /// 信息输出委托,可以传null
        /// </summary> 
        void Output(string msg, Exception ex) {
            if (ex == null) {
                Log.Info(msg);
            } else {
                Log.Info(ex.ToString());
            }
        }
        /// <summary>
        /// 模拟处理数据
        /// </summary>
        /// <param name="progressInof">进度信息</param>
        /// <param name="data">数据</param>
        /// <returns></returns>
        async Task Execute(string progressInof, string data) {
            Log.Info($"{progressInof},开始处理:{data}");
            await Task.Delay(3000); //模拟处理毫时业务
            Log.Info($"{progressInof},{data}处理完毕");
        }
View Code

 

标签:异步,Task,C#,并行执行,token,output,parallelCount
From: https://www.cnblogs.com/luludongxu/p/18307024

相关文章

  • Codeforces Round 957 (Div. 3)
    知识点1.几个数相乘时,更小的数增加会比更大的数增加得到的乘积来得大题解A.OnlyPluses1.几个数相乘时,当更小的数增大时,得到的乘积会比更大的数增大来得大,也就是更小的数字权重会比较大,那么在5次+1的过程中,每次找最小值++即可#include<bits/stdc++.h>#defineintlonglon......
  • Office文件打不开如何处理
        在快节奏的现代办公环境中,MicrosoftOffice无疑是我们的得力助手,无论是起草报告、整理数据还是制作演示文稿,它都在背后默默支撑着我们的工作与学习。然而,当有一天,你突然发现重要的Office文档无法打开,屏幕上的错误信息仿佛一道无形的墙,阻隔了你与辛勤工作成果之间的......
  • Python学习笔记—100页Opencv详细讲解教程
    目录1创建和显示窗口...-4-2加载显示图片...-6-3保存图片...-7-4视频采集...-8-5视频录制...-11-6控制鼠标...-12-7TrackBar控件...-14-8.RGB和BGR颜色空间...-16-9.HSV和HSL和YUV..-17-10颜色空间的转化...-18-11mat的深......
  • 【工具介绍】nuclei-yaml脚本编写
    文章目录YAML脚本语法基础nuclei模板语法常见使用场景命令执行sql延时注入任意文件读取跨站脚本攻击反序列化漏洞弱密码文件上传nuclei是一款基于Go语言开发的快速、灵活的自动化漏洞扫描工具,它使用YAML格式的模板来定义扫描规则。YAML(YAMLAin’tMarkupLa......
  • Vue3 - 微信公众号H5网站使用微信扫一扫(微信扫码),苹果报错 {“errMsg“:“scanQRCode
    前言关于此问题网上的教程都无法解决,如果您的报错信息与我相似,即可解决。在vue3|nuxt3微信公众号网页开发中,微信移动端h5网页使用JS-SDK中的“微信扫码(微信扫一扫)”wx.scanQRCode接口,苹果ios系统真机测试时出现报错:“errMsg”:“scanQRCode:thepermissi......
  • XX2104 培训【C++解决】
    描述某培训机构的学员有如下信息:姓名(字符串)年龄(周岁,整数)去年NOIP成绩(整数,且保证是5的倍数)经过为期一年的培训,所有同学的成绩都有所提高,提升了20%(当然NOIP满分是600分,不能超过这个得分)。输入学员信息,请设计一个结构体储存这些学生信息,并设计一个函数模拟培训......
  • 如何在Mac上隐藏APP? 在Mac上隐藏不用的APP小技巧
    在Mac电脑中我们每天要使用很多APP,虽然Mac切换APP窗口的快捷键非常方便,但同时使用几个APP窗口是不是特别容易搞混?看起来乱糟糟的。下面我们分享在Mac上隐藏不用的APP小技巧,让用户摆脱混乱的APP窗口。1、在Mac电脑中,打开你想要保留的APP;2、点击屏幕顶部菜单栏中APP名称,3、选择下拉......
  • 【CTF入门】BUUCTF Misc刷题(持续更新)
    【CTF入门】BUUCTFMisc刷题签到点开发现签到题直接把flag交出来了,直接复制提交即可考点:了解CTF中flag的格式一般为flag{}金三胖下载文件,发现里面是一张gif图片,我们查看一下发现总有东西一闪而过这里我们介绍第一个在Misc图像隐写中非常常用的工具——StegSolveStegSolve......
  • Django导出EXCEL并确保表头左右两列显示
    以下是导出EXCEL确保表头左右两列显示正确值的代码示例:fromopenpyxlimportWorkbookfromopenpyxl.stylesimportAlignment#创建一个新的工作簿和工作表wb=Workbook()ws=wb.active#模拟订单头信息(替换为您的实际数据获取方法)order_header={'od_no':'SO......
  • DC7渗透报告
    概述测试目的测试范围序号系统IP1本机192.168.152.1282DC7192.168.152.138详细测试流程1、发现测试目标直接就给出来了2、信息收集3、漏洞利用访问80端口,作者提示用字典暴力破解是不可以的,得要跳出思维限制根据下面的作者信息,到github上面搜索发现了数据库配置文件登录后台失败、......