我们会有很多异步方法,通常,调用了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,则多个控制器同时进行,相互不干扰。
祝您用餐愉快。