如何使ConcurrentExclusiveSchedulerPair与async和await一起使用

问题描述 投票:1回答:2

我有以下代码:

        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返回已完成的任务并且从ConcurrentExclusiveSchedulerPair的角度来看它确实完成了执行的原因。我也知道一些解决方法,但是有没有正确的方法来异步运行此模式?

c# multithreading task task-parallel-library
2个回答
1
投票

TaskScheduler的概念是在异步/等待出现之前设计的,最终与之不兼容。您可以在此处看到一个证明这种不兼容性的实验:How to run a Task on a custom TaskScheduler using await?

可用于控制异步/等待行为的抽象是SynchronizationContext。它与SynchronizationContext非常相似。实际上很多人一直在想为什么我们都需要:TaskScheduler

如果您对What is the conceptual difference between SynchronizationContext and TaskScheduler之类的东西感兴趣,可以在此处找到实现:SingleThreadSynchronizationContext


0
投票

[Await, SynchronizationContext, and Console AppsAwait, 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之后将在同一并发调度程序上继续执行。

但是,语义可能令人惊讶,因为SynchronizationContext与任务计划程序一起工作的方式是null方法被拆分为multiple个任务。每个TaskScheduler是一个“拆分”点,该方法被分解。而[[仅那些较小的任务实际上是ThreadTask计划的

因此,在您的情况下,您的代码正在启动10个await调用,每个调用均在并发调度程序上运行,并且每个调用都达到async点。然后代码在调度程序上调用async,告诉它不接受更多任务。然后,当await完成时,他们将TaskScheduler方法继续(作为一项任务)安排到该任务计划程序,该任务计划程序已经完成。

因此,虽然从技术上讲ThreadTask设计为可与await一起使用,但实际上很少有人以这种方式使用它。特别是,“并发的”和“排他的”任务计划程序可能具有令人惊讶的语义,因为由于Complete而暂停的方法不算作任务计划程序的“运行”。

© www.soinside.com 2019 - 2024. All rights reserved.