如果您使用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 的使用。如果您write TAP wrappers for your EAP members,您的async 代码将更“自然”(即更简单)。
这非常复杂,我建议将其放入一个单独的类中,但您需要先决定如何处理(和显示)错误。