我有一个名为Refresh的异步操作。如果在第一个刷新完成之前进行第二个刷新调用,我需要将其排队。这是我目前的代码:
public async Task Refresh(RefreshArgs refreshArgs)
{
await EnqueueRefreshTask(refreshArgs);
}
private Queue<RefreshArgs> refreshQueue =
new Queue<RefreshArgs>();
private async Task EnqueueRefreshTask(RefreshArgs refreshArgs)
{
refreshQueue.Enqueue(refreshArgs);
await ProcessRefreshQueue();
}
private Task currentRefreshTask = null;
private async Task ProcessRefreshQueue()
{
if ((currentRefreshTask == null) || (currentRefreshTask.IsCompleted))
{
if (refreshQueue.Count > 0)
{
var refreshArgs = refreshQueue.Dequeue();
currentRefreshTask = DoRefresh(refreshArgs);
await currentRefreshTask;
await ProcessRefreshQueue();
}
}
}
private async Task DoRefresh(RefreshArgs refreshArgs)
{
// Lots of code here, including calls to a server that are executed with await.
// Code outside my control may make another Refresh(args) call while this one is still processing.
// I need this one to finish before processing the next.
}
这个方法可以实现,但是我不确定是否使用Tasks来做这个任务是最好的方式。有什么建议吗?
更新:
我尝试使用ActionBlock:
public async Task Refresh(RefreshArgs refreshArgs)
{
if (refreshActionBlock == null)
{
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions();
executionDataflowBlockOptions.MaxMessagesPerTask = 1;
executionDataflowBlockOptions.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
refreshActionBlock = new ActionBlock<RefreshArgs>(args => DoRefresh(args), executionDataflowBlockOptions);
}
await refreshActionBlock.SendAsync(refreshArgs);
}
这将队列化DoRefresh,并允许其在UI线程中运行(这是我需要的)。问题在于SendAsync不等待DoRefresh的工作。
SendAsync:“异步地向目标消息块提供消息,允许延迟”。我只等待发送,而不是操作本身。
这样做并不能按预期工作:
await Refresh(RefreshArgs.Something);
// other code goes here. It expects the first refresh to be finished.
await Refresh(RefreshArgs.SomethingElse);
// other code goes here. It expects the second refresh to be finished.
在ActionBlock中,第二次刷新会被排入队列,但在完成刷新之前,等待的操作已经继续执行了。我需要它们在DoRefresh工作完成后返回。
ActionBlock
替换掉所有这些。 - Stephen ClearyQueue
不是线程安全的;您应该使用BlockingCollection
代替。 - Servy