如何使用 async-await 创建一个从不一次执行多个任务的调度程序? [英] How do I create a scheduler which never executes more than one Task at a time using async-await?

查看:18
本文介绍了如何使用 async-await 创建一个从不一次执行多个任务的调度程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to implement a class or pattern that ensures that I never execute more than one Task at a time for a certain set of operations (HTTP calls). The invocations of the Tasks can come from different threads at random times. I want to make use of the async-await pattern so that the caller can handle exceptions by wrapping the call in a try-catch.

以下是预期执行流程的说明:

Here's an illustration of the intended flow of execution:

来自调用方的伪代码:

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

此处的 Task 类可能是 Action 类,具体取决于解决方案.

The Taskclass here might instead be an Action class depending on the solution.

请注意,当我在这个问题中使用时间表"这个词时,我不一定使用它与 .NET 任务计划程序.我不太了解 async-await 库,无法知道从什么角度以及使用什么工具来解决这个问题.TaskScheduler 在这里可能是相关的,也可能不是.我已阅读 TAP 模式 文档并找到了模式几乎解决了这个问题,但还没有完全解决(关于交错的章节).

Note that I when I use the word "Schedule" in this question I'm not necessarily using it with relation to the .NET Task Scheduler. I don't know the async-await library well enough to know at what angle and with what tools to approach this problem. The TaskScheduler might be relevant here, and it may not. I've read the TAP pattern document and found patterns that almost solve this problem, but not quite (the chapter on interleaving).

推荐答案

有一个新的 ConcurrentExclusiveSchedulerPair 输入 .NET 4.5(我不记得它是否包含在异步 CTP 中),以及您可以使用其 ExclusiveScheduler 将执行限制为一次一个 Task.

There is a new ConcurrentExclusiveSchedulerPair type in .NET 4.5 (I don't remember if it was included in the Async CTP), and you can use its ExclusiveScheduler to restrict execution to one Task at a time.

考虑将您的问题构建为数据流.只需将 TaskScheduler 传递到您想要限制的数据流部分的块选项中很容易.

Consider structuring your problem as a Dataflow. It's easy to just pass a TaskScheduler into the block options for the parts of the dataflow you want restricted.

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

If you don't want to (or can't) use Dataflow, you can do something similar yourself. Remember that in TAP, you always return started tasks, so you don't have the "creation" separated from the "scheduling" like you do in TPL.

您可以使用 ConcurrentExclusiveSchedulerPair 来安排 Actions(或 async 没有返回值的 lambdas),如下所示:

You can use ConcurrentExclusiveSchedulerPair to schedule Actions (or async lambdas without return values) like this:

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 的单个实例仅协调排队到其调度程序的Task.ConcurrentExclusiveSchedulerPair 的第二个实例将独立于第一个实例,因此您必须确保在您想要协调的系统的所有部分中使用相同的实例.
  • async 方法 - 默认情况下 - 在启动它的同一个 TaskScheduler 上恢复.所以这意味着如果一个 async 方法调用另一个 async 方法,子"方法将继承"父的 TaskScheduler.任何 async 方法都可以通过使用 ConfigureAwait(false) 选择不继续其 TaskScheduler(在这种情况下,它直接在线程池上继续).
  • A single instance of ConcurrentExclusiveSchedulerPair only coordinates Tasks that are queued to its schedulers. A second instance of ConcurrentExclusiveSchedulerPair would be independent from the first, so you have to ensure the same instance is used in all parts of your system you want coordinated.
  • An async method will - by default - resume on the same TaskScheduler that started it. So this means if one async method calls another async method, the "child" method will "inherit" the parent's TaskScheduler. Any async method may opt out of continuing on its TaskScheduler by using ConfigureAwait(false) (in that case, it continues directly on the thread pool).

这篇关于如何使用 async-await 创建一个从不一次执行多个任务的调度程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆