是否可以通过使用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

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

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

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

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

所以我的意思是Task.whena可以是并行的还是只并发的?

理论上,您可以以并行方式使用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这样的阻塞方法。

您不应该试图自己控制并行度。

比显式创建和启动线程更好的方法是对使用并行

Parallel.For(0, 50, i => { Thread.Sleep(1000); } );

然后,任务并行机制自动确定线程的最佳数量(基于可用内核的数量(,并在这些线程之间分配任务。

这也减少了创建比可以并行执行的线程更多的线程的开销。

最新更新