普通的异步队列可以回看我之前一篇博客:https://www.cnblogs.com/log9527blog/p/16517315.html
但是之前实现的异步队列中,任务如果出现await等待,会认为该任务已经完成,并且开始下一个任务。所有为了实现异步队列中等待await执行完毕再执行下一个任务,下面重写了新的异步队列:
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace Text
{
/// <summary>
/// 异步任务队列
/// <para>同步执行,等待委托内的await完成再执行下一个委托,并且自动取消中间的任务</para>
/// </summary>
public class SynchronizeTaskQueue
{
#region 执行
/// <summary>
/// 执行多个同步操作(同步执行,取消中间未执行的任务,传进来的委托需要try...catch...)
/// </summary>
/// <param name="func">异步操作</param>
public void ExecuteFromResult(Func<Task> func)
{
AddPendingAwaitTaskToQueue(func);
Task.Run(async () =>
{
await ExcuteTaskQueue();
});
}
#endregion
#region 添加任务
/// <summary>
/// 添加待执行任务到队列
/// </summary>
/// <param name="func"></param>
/// <returns></returns>
private void AddPendingAwaitTaskToQueue(Func<Task> func)
{
// 添加队列,加锁。
lock (_funcQueue)
{
// 添加任务
_funcQueue.Enqueue(func);
var newTask = new Task<Task>(async () =>
{
await InternalAwaitRunning();
});
_taskQueue.Enqueue(newTask);
}
}
/// <summary>
/// 执行队列任务
/// </summary>
/// <returns></returns>
private async Task ExcuteTaskQueue()
{
try
{
await _semaphoreSlim.WaitAsync();
var count = _taskQueue.Count;
Task<Task> task = null;
for (int i = 0; i < count; i++)
{
// 移出所有的线程,并且只执行最后一个
_taskQueue.TryDequeue(out task);
// 移出中间不执行的委托
if (i < count - 1)
{
_funcQueue.TryDequeue(out Func<Task> func);
}
}
if (task == null) return;
task.Start();
await await task;
}
finally
{
_semaphoreSlim.Release();
}
}
#endregion
#region 内部运行
/// <summary>
/// 执行委托
/// </summary>
/// <returns></returns>
private async Task InternalAwaitRunning()
{
if (TryGetNextAwaitTask(out var func))
{
await func();
}
}
/// <summary>
/// 获取
/// </summary>
/// <param name="func"></param>
/// <returns></returns>
private bool TryGetNextAwaitTask(out Func<Task> func)
{
func = null;
while (_funcQueue.Count > 0)
{
//获取并从队列中移除任务
if (_funcQueue.TryDequeue(out func))
{
return true;
}
}
return false;
}
#endregion
#region 属性及字段
/// <summary>
/// 控制当出现多个任务在队列中时,限制等待上一个任务执行完成才到下一个
/// </summary>
private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1);
/// <summary>
/// 线程队列
/// </summary>
private readonly ConcurrentQueue<Task<Task>> _taskQueue = new ConcurrentQueue<Task<Task>>();
/// <summary>
/// 委托队列
/// </summary>
private readonly ConcurrentQueue<Func<Task>> _funcQueue = new ConcurrentQueue<Func<Task>>();
#endregion
}
}
上面的异步队列会同步执行,并且自动取消中间未执行的任务。