首页 > 解决方案 > 是否可以通过使用 Task.Delay 强制一个新线程来确定任务的并行性?

问题描述

我试图确定任务可以根据任务调度程序做出的决定并行运行。我被告知这并不能证明这一点:

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var tasks = new List<Task>();
        for (int i = 0; i < 50; i++)
        {
            tasks.Add(Task.Run(async () =>
            {
                await Task.Delay(1000);
            }));
        }

        await Task.WhenAll(tasks);
        stopwatch.Stop();
        // should be 50000 without any parallelism
        var elapsedTime = stopwatch.ElapsedMilliseconds; // on my machine actual result is around 10000

所以我现在对此很困惑。执行时间的最终结果怎么可能小于执行每个任务所需的时间 * 任务数量而不证明某种程度的并行性?

标签: c#.netasp.net-coretask-parallel-library

解决方案


我正在尝试根据任务调度程序做出的决定确定任务可以并行运行......执行时间的最终结果怎么可能少于执行每个任务所需的时间 * 任务的数量而不是证明某种程度的并行性?

它证明了并发,可能是异步并发,也可能是并行。在这种情况下,您的代码正在执行异步并发。

需要注意的是,任务调度程序仅适用于正在运行的任务——即实际执行代码或被阻塞的任务。运行的线程await Task.Delay在延迟时间内既不执行代码也不阻塞。

所以我的意思是 Task.whenall 可以并行还是仅并发?

您可以 - 理论上 -WhenAll以并行方式使用。您只需将代码更改为阻塞而不是异步,它将并行运行:

var stopwatch = new Stopwatch();
stopwatch.Start();
var tasks = new List<Task>();
for (int i = 0; i < 50; i++)
{
  tasks.Add(Task.Run(async () =>
  {
    Thread.Sleep(1000);
  }));
}

await Task.WhenAll(tasks);
stopwatch.Stop();
var elapsedTime = stopwatch.ElapsedMilliseconds;

在这种情况下,您的代码是并行的。像这样使用Task.WhenAll会起作用,但这是不寻常的。通常,并行代码使用诸如Task.WaitAll.


推荐阅读