如何使 ConcurrentExclusiveSchedulerPair 使用 async 和 await
How to make ConcurrentExclusiveSchedulerPair work with async and await
我有以下代码:
static async Task Main()
{
ConcurrentExclusiveSchedulerPair concurrentExclusiveSchedulerPair = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 4);
var factory = new TaskFactory(concurrentExclusiveSchedulerPair.ConcurrentScheduler);
for (int i = 0; i < 10; i++)
{
factory.StartNew(ThreadTask);
}
concurrentExclusiveSchedulerPair.Complete();
await concurrentExclusiveSchedulerPair.Completion;
Console.WriteLine("Completed");
}
private static async Task ThreadTask()
{
var random = new Random();
await Task.Delay(random.Next(100, 200));
Console.WriteLine($"Finished {Thread.CurrentThread.ManagedThreadId}");
}
并且程序在任务完成之前完成执行。我理解为什么它会在 ThreadTask
returns 完成任务时发生,并且从 ConcurrentExclusiveSchedulerPair
的角度来看它确实完成了执行。我也知道一些解决方法,但是有什么正确的方法可以 运行 这种模式与异步?
TaskScheduler
的概念是在 async/await 出现之前提出的,但最终与 async/await 不兼容。您可以在此处查看证明这种不兼容性的实验:How to run a Task on a custom TaskScheduler using await?
可用于控制 async/await 行为的抽象是 SynchronizationContext
. It is quite similar to a TaskScheduler
. So much actually that some people have been wondering why we need both: What is the conceptual difference between SynchronizationContext and TaskScheduler。
如果您对 SingleThreadSynchronizationContext
之类的东西感兴趣,您可以在此处找到实现:Await, SynchronizationContext, and Console Apps
TaskScheduler
与 async
/await
兼容,但某些行为可能令人惊讶。
当 await
捕获其上下文时,it captures the current SynchronizationContext
unless it is null
, in which case it captures the current TaskScheduler
。因此,ThreadTask
将开始使用并发调度程序执行,并且在其 await
之后它将在同一个并发调度程序上恢复。
然而,语义可能会令人惊讶,因为 async
与任务调度程序一起工作的方式是 async
方法被拆分为 多个 任务.每个 await
是方法被分解的 "split" 点。 只有那些较小的任务才是TaskScheduler
.
实际安排的任务
所以在你的例子中,你的代码开始了 10 ThreadTask
次调用,每个 运行 在并发调度程序上,并且每个都命中一个 await
点。然后代码在调度程序上调用 Complete
,告诉它不再接受任何任务。然后当 await
完成时,他们将 async
方法继续(作为任务)安排到已经完成的任务调度程序。
因此,虽然从技术上讲 await
旨在与 TaskScheduler
一起使用,但实际上很少有人那样使用它。特别是,"concurrent" 和 "exclusive" 任务调度程序可能具有令人惊讶的语义,因为由于 await
而暂停的方法对于任务调度程序来说不算作 "running"。
我有以下代码:
static async Task Main()
{
ConcurrentExclusiveSchedulerPair concurrentExclusiveSchedulerPair = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 4);
var factory = new TaskFactory(concurrentExclusiveSchedulerPair.ConcurrentScheduler);
for (int i = 0; i < 10; i++)
{
factory.StartNew(ThreadTask);
}
concurrentExclusiveSchedulerPair.Complete();
await concurrentExclusiveSchedulerPair.Completion;
Console.WriteLine("Completed");
}
private static async Task ThreadTask()
{
var random = new Random();
await Task.Delay(random.Next(100, 200));
Console.WriteLine($"Finished {Thread.CurrentThread.ManagedThreadId}");
}
并且程序在任务完成之前完成执行。我理解为什么它会在 ThreadTask
returns 完成任务时发生,并且从 ConcurrentExclusiveSchedulerPair
的角度来看它确实完成了执行。我也知道一些解决方法,但是有什么正确的方法可以 运行 这种模式与异步?
TaskScheduler
的概念是在 async/await 出现之前提出的,但最终与 async/await 不兼容。您可以在此处查看证明这种不兼容性的实验:How to run a Task on a custom TaskScheduler using await?
可用于控制 async/await 行为的抽象是 SynchronizationContext
. It is quite similar to a TaskScheduler
. So much actually that some people have been wondering why we need both: What is the conceptual difference between SynchronizationContext and TaskScheduler。
如果您对 SingleThreadSynchronizationContext
之类的东西感兴趣,您可以在此处找到实现:Await, SynchronizationContext, and Console Apps
TaskScheduler
与 async
/await
兼容,但某些行为可能令人惊讶。
当 await
捕获其上下文时,it captures the current SynchronizationContext
unless it is null
, in which case it captures the current TaskScheduler
。因此,ThreadTask
将开始使用并发调度程序执行,并且在其 await
之后它将在同一个并发调度程序上恢复。
然而,语义可能会令人惊讶,因为 async
与任务调度程序一起工作的方式是 async
方法被拆分为 多个 任务.每个 await
是方法被分解的 "split" 点。 只有那些较小的任务才是TaskScheduler
.
所以在你的例子中,你的代码开始了 10 ThreadTask
次调用,每个 运行 在并发调度程序上,并且每个都命中一个 await
点。然后代码在调度程序上调用 Complete
,告诉它不再接受任何任务。然后当 await
完成时,他们将 async
方法继续(作为任务)安排到已经完成的任务调度程序。
因此,虽然从技术上讲 await
旨在与 TaskScheduler
一起使用,但实际上很少有人那样使用它。特别是,"concurrent" 和 "exclusive" 任务调度程序可能具有令人惊讶的语义,因为由于 await
而暂停的方法对于任务调度程序来说不算作 "running"。