不卡主线程,N个异步方法后台运行,且需要按时序顺序执行,要怎么写?

36 篇文章 16 订阅

我们会有很多异步方法,通常,调用了N个异步方法后,哪个先执行完,哪个后执行完,是不确定的。

场景:

若需要确保不影响主线程,即不卡主线程,仍然让这些耗时的异步方法在后台执行,且需要让这些异步方法,按一定的先后顺序(时序)执行,那么要怎么办呢?
 

下面直接提供一个类给大家针对上述场景使用。直接上代码,抄过去即可直接使用。

using System;

namespace Zhongzhou.TaskFlow
{
    /// <summary>
    /// 作业流程任务控制器
    /// </summary>
    /// <creator>marc</creator>
    public interface ITaskController
    {
        /// <summary>
        /// 表示作业处理完成。不论该作业的处理结果是成功、取消、还是失败,仅表示已处理结束。
        /// </summary>
        event EventHandler<TaskInfo> Processed;
        /// <summary>
        /// 表示作业已开始运行,但未结束
        /// </summary>
        event EventHandler<TaskInfo> Started;
        /// <summary>
        /// 入队一个线程,先进先出
        /// </summary>
        /// <param name="taskInfo"></param>
        void Enqueue(TaskInfo taskInfo);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Zhongzhou.TaskFlow
{
    /// <summary>
    /// 表示任务信息类
    /// </summary>
    public class TaskInfo
    {
        /// <summary>
        /// 表示待执行的作业
        /// </summary>
        public Task Task { get; set; }

        /// <summary>
        /// 任务名称
        /// </summary>
        public string TaskName { get; set; }
        /// <summary>
        /// 任务数据
        /// </summary>
        public object TaskData { get; set; }
    }
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Zhongzhou.TaskFlow
{
    /// <inheritdoc cref="ITaskController"/>
    public class TaskController : ITaskController
    {
        private readonly ConcurrentQueue<TaskInfo> _tasks = new ConcurrentQueue<TaskInfo>();
        private bool _isRunning = false;

        /// <summary>
        /// 表示任务控制列表。几个通道,就有几个控制器
        /// </summary>
        private static readonly ConcurrentDictionary<int, TaskController> _controllers = new ConcurrentDictionary<int, TaskController>();

        /// <inheritdoc/>
        public event EventHandler<TaskInfo> Processed;
        /// <inheritdoc/>
        public event EventHandler<TaskInfo> Started;

        /// <inheritdoc cref="TaskController"/>
        protected TaskController()
        {

        }

        /// <summary>
        /// 使用指定通道唯一实例。若已有实例则使用第一个实例,否则创建0通道的实例。
        /// </summary>
        /// <param name="channel">表示通道。几个通道,就有几个实例控制器。通道通常根据左右片玻璃来设定。</param>
        /// <returns></returns>
        public static ITaskController Instance(int channel = 0)
        {
            if (_controllers.ContainsKey(channel))
            {
                return _controllers[channel];
            }
            else
            {
                lock (typeof(object))
                {
                    TaskController instance = new TaskController();
                    _controllers.TryAdd(channel, instance);
                    return instance;
                }
            }
        }

        /// <inheritdoc/>
        public void Enqueue(TaskInfo taskInfo)
        {
            if (!taskInfo.IsIn(_tasks))
            {
                _tasks.Enqueue(taskInfo);
            }

            Run();
        }

        /// <summary>
        /// 运行
        /// </summary>
        private void Run()
        {
            if (_isRunning || _tasks.Count == 0)
            {
                return;
            }

            _isRunning = true;

            if (!_tasks.TryDequeue(out TaskInfo taskInfo))
            {
                return;
            }
            var task = taskInfo.Task;
            task.Start(TaskScheduler.Current);
            OnStarted(this, taskInfo);
            task.ContinueWith((t) =>
            {
                OnProcessed(this, taskInfo);

                _isRunning = false;
                Run();
            });
        }

        /// <inheritdoc cref="Processed"/>
        protected virtual void OnStarted(object sender, TaskInfo e)
        {
            this.Started?.Invoke(sender, e);
        }

        /// <inheritdoc cref="Processed"/>
        protected virtual void OnProcessed(object sender, TaskInfo e)
        {
            this.Processed?.Invoke(sender, e);
        }
    }
}

调用方式如下:

Task<ExecuteResult> task = new Task<ExecuteResult>(() =>
{
    return Communicator.ReportHandshakeAsync(Addresses.StoreJobDataReport, model).Result;
});
TaskController.Instance().Enqueue(new TaskInfo { Task = task, TaskName = MethodBase.GetCurrentMethod().Name, TaskData = model.JobDataBlock.PanelID });

return await task;

 

其中有个channel参数,该参数用于指示控制器的分类标记,在每个独立的标记下,N个异步方法,一定会按时先进先出的方式执行。若有多个channel,则多个控制器同时进行,相互不干扰。

祝您用餐愉快。 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值