如果您使用async
/ await
,则不需要另一个线程(因为您没有 CPU 绑定处理)。
在您的情况下,听起来您只需要一个异步委托队列。异步委托的自然类型是Func<Task>
(没有返回值)或Func<Task<T>>
(有返回值)。不幸的是,这个小技巧在这一点上并不为人所知。
因此,声明一个异步委托队列:
private readonly Queue<Func<Task>> queue = new Queue<Func<Task>>();
然后,您可以拥有一个仅(异步)处理队列的“顶级”任务:
private Task queueProcessor;
只要没有更多项目,queueProcessor
就可以。null
只要不是null
,它将代表此方法:
private async Task ProcessQueue()
{
try
{
while (queue.Count != 0)
{
Func<Task> command = queue.Dequeue();
try
{
await command();
}
catch (Exception ex)
{
// Exceptions from your queued tasks will end up here.
throw;
}
}
}
finally
{
queueProcessor = null;
}
}
您的Enqueue
方法将如下所示:
private void Enqueue(Func<Task> command)
{
queue.Enqueue(command);
if (queueProcessor == null)
queueProcessor = ProcessQueue();
}
现在,我有这样的异常处理设置:任何引发异常的排队命令都会导致队列处理器停止处理(具有相同的异常)。这可能不是您的应用程序的最佳行为。
您可以像这样使用它(当然,使用 lambda 或实际方法):
Enqueue(async () =>
{
ShowProgressIndicator = true;
ModelData = await myProxy.DownloadStringTaskAsync();
ShowProgressIndicator = false;
});
注意使用DownloadStringTaskAsync
. 如果您为您的 EAP 成员编写 TAP 包装器,您的async
代码将更加“自然”(即更简单)。
这非常复杂,我建议将其放入一个单独的类中,但您需要先决定如何处理(和表面)错误。