0

在 wp8 中排队复杂任务的正确方法是什么?

任务包括以下内容:

  1. ProgressIndicator通过更新模型变量显示
  2. 获取或存储数据到 wcf 服务 ( UploadStringAsync)
  3. 使用来自 的结果更新潜在的数据绑定模型UploadStringCompleted
  4. ProgressIndicator通过更新模型变量隐藏

目前,我一直在使用一个拥有命令对象队列的类,运行一个线程,如果它尚未运行,则在添加项目时启动该线程。

但是,我在等待代码停止运行的任务或子任务时遇到问题。

以前我使用过异步等待,但是在几个级别下,行为变得越来越不可预测。

我想要的是能够创建和排队命令对象的主线程。命令对象应该一次运行一个,在前一个完全完成之前不要开始新的。如果需要,命令对象应该能够使用调度程序访问主线程。

4

1 回答 1

6

如果您使用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代码将更加“自然”(即更简单)。

这非常复杂,我建议将其放入一个单独的类中,但您需要先决定如何处理(和表面)错误。

于 2013-05-20T12:54:06.833 回答