如何使用 async-await 创建一个从不一次执行多个任务的调度程序? [英] How do I create a scheduler which never executes more than one Task at a time using 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 Task
class 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
来安排 Action
s(或 async
没有返回值的 lambdas),如下所示:
You can use ConcurrentExclusiveSchedulerPair
to schedule Action
s (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 coordinatesTask
s that are queued to its schedulers. A second instance ofConcurrentExclusiveSchedulerPair
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 sameTaskScheduler
that started it. So this means if oneasync
method calls anotherasync
method, the "child" method will "inherit" the parent'sTaskScheduler
. Anyasync
method may opt out of continuing on itsTaskScheduler
by usingConfigureAwait(false)
(in that case, it continues directly on the thread pool).
这篇关于如何使用 async-await 创建一个从不一次执行多个任务的调度程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!