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

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

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

异步并行执行器

复制代码
    /// <summary>
    /// 异步并行执行器,可以将任务并行执行,提高执行速度
    /// </summary>
    public class AsyncParallelExecutor<T> {
        /// <summary>
        /// 对单一数据进行处理的业务逻辑委托
        /// </summary>
        /// <param name="taskID">异步任务ID</param>
        /// <param name="index">进度索引</param>
        /// <param name="arg">参数</param>
        /// <returns>是否继续处理下一条</returns>
        public delegate Task<bool> ExecuteFunc(int taskID, int index, T arg);
        /// <summary>
        /// 数据的总数量
        /// </summary>
        public readonly int TotalCount;
        readonly object _lock = new object();
        readonly Queue<T> queue = new Queue<T>();
        readonly ExecuteFunc _executeFunc;
        /// <summary>
        /// 传入参数集合和业务委托,创建一个异步并行执行器
        /// </summary>
        /// <param name="args">参数集合</param>
        /// <param name="executeFunc">处理单位数据的业务委托</param>
        public AsyncParallelExecutor(IEnumerable<T> args, ExecuteFunc executeFunc) {
            foreach (var arg in args) {
                queue.Enqueue(arg);
            }
            TotalCount = queue.Count;
            _executeFunc = executeFunc;
        }
        /// <summary>
        /// 开始执行并行任务
        /// </summary>
        /// <param name="taskCount">使用的异步任务个数</param>
        /// <returns></returns>
        public async Task Start(int taskCount = 2) {
            Task[] tasks = new Task[taskCount];
            for (int i = 0; i < taskCount; i++) {
                tasks[i] = AsyncTask(i);
            }
            await Task.WhenAll(tasks);
        }
        Task AsyncTask(int taskID) {
            return Task.Run(async () => {
                while (true) {
                    var (success, index) = TryGet(out T val);
                    if (success == false) {
                        break;
                    }
                    bool ret = await _executeFunc(taskID, index, val);
                    if (ret == false) {
                        break;
                    }
                }
            });
        }
        (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
复制代码

使用方法

复制代码
        AsyncParallelExecutor<int> ape;
        CancellationToken Token;
        public async Task Start() {
            var ps = Enumerable.Range(0, 20); //模拟要业务参数集合
            ape = new AsyncParallelExecutor<int>(ps, Execute);
            await ape.Start();
        }
        async Task<bool> Execute(int taskID, int index, int val) {
            if (Token.IsCancellationRequested) {
                return false; //中断操作
            }
            Thread.Sleep(3000);  //模拟毫时操作
            Logger.Info($"任务ID={taskID},进度={index}/{ape.TotalCount},参数={val}");
            await Task.CompletedTask;
            return true;
        }
View Code
复制代码

需要注意的是,具体执行操作的方法是异步的,如果要统计数据,累加器记得用原子操作累加

 

posted @   WmW  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
历史上的今天:
2017-07-17 C#驱动mysql明明数值不为空却一直说DBNull.Value的诡异情况
点击右上角即可分享
微信分享提示