19

我想实现一个类或模式,以确保对于一组特定的操作(HTTP 调用)一次不会执行多个任务。任务的调用可以随机来自不同的线程。我想利用异步等待模式,以便调用者可以通过将调用包装在 try-catch 中来处理异常。

这是预期执行流程的图示:

在此处输入图像描述

来自调用者的伪代码:

try {
    Task someTask = GetTask();
    await SomeScheduler.ThrottledRun(someTask);
} 
catch(Exception ex) { 
    // Handle exception
}

这里的Task类可能是一个Action取决于解决方案的类。

请注意,当我在这个问题中使用“Schedule”这个词时,我不一定会使用与.NET Task Scheduler相关的词。我不太了解 async-await 库,无法知道以什么角度以及使用什么工具来解决这个问题。TaskScheduler 在这里可能是相关的,也可能不是。我已经阅读了TAP 模式文档,发现几乎可以解决这个问题的模式,但并不完全(关于交错的章节)。

4

1 回答 1

30

.NET 4.5 中有一种新ConcurrentExclusiveSchedulerPair类型(我不记得它是否包含在 Async CTP 中),您可以使用它ExclusiveScheduler来限制一次执行一个Task

考虑将您的问题构建为Dataflow。很容易将 a 传递给TaskScheduler您想要限制的数据流部分的块选项。

如果您不想(或不能)使用 Dataflow,您可以自己做类似的事情。请记住,在 TAP 中,您总是返回已启动的任务,因此您不会像在 TPL 中那样将“创建”与“调度”分开。

您可以像这样ConcurrentExclusiveSchedulerPair安排Actions(或async没有返回值的 lambda):

public static ConcurrentExclusiveSchedulerPair schedulerPair =
    new ConcurrentExclusiveSchedulerPair();
public static TaskFactory exclusiveTaskFactory =
    new TaskFactory(schedulerPair.ExclusiveScheduler);
...
public static Task RunExclusively(Action action)
{
  return exclusiveTaskFactory.StartNew(action);
}
public static Task RunExclusively(Func<Task> action)
{
  return exclusiveTaskFactory.StartNew(action).Unwrap();
}

对此有几点需要注意:

  • ConcurrentExclusiveSchedulerPair只有坐标s的单个实例Task排队到其调度程序。第二个实例ConcurrentExclusiveSchedulerPair将独立于第一个实例,因此您必须确保在要协调的系统的所有部分中使用相同的实例。
  • 一个async方法将 - 默认情况下 - 在TaskScheduler启动它的相同处恢复。所以这意味着如果一个async方法调用另一个async方法,“子”方法将“继承”父方法的TaskScheduler. 任何async方法都可以选择不继续TaskScheduler使用ConfigureAwait(false)(在这种情况下,它直接在线程池上继续)。
于 2012-08-22T08:50:39.040 回答