我刚刚对
Task.WhenAll
方法,在运行时。NET Core 3.0。我通过了一个简单的
Task.Delay
任务作为一个单一的论点
任务。When All
,我希望包装好的任务的行为与原始任务相同。但事实并非如此。原始任务的延续是异步执行的(这是可取的),多个任务的延续
Task.WhenAll(task)
包装器一个接一个地同步执行(这是不理想的)。
这是一个
demo
这种行为。四个工作任务正在等待相同的任务
任务。延误
完成任务,然后继续进行繁重的计算(由
Thread.Sleep
).
var task = Task.Delay(500);
var workers = Enumerable.Range(1, 4).Select(async x =>
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} before await");
await task;
//await Task.WhenAll(task);
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} after await");
Thread.Sleep(1000); // Simulate some heavy CPU-bound computation
}).ToArray();
Task.WaitAll(workers);
这是输出。这四个延续按预期在不同线程中并行运行。
05:23:25.511 [1] Worker1 before await
05:23:25.542 [1] Worker2 before await
05:23:25.543 [1] Worker3 before await
05:23:25.543 [1] Worker4 before await
05:23:25.610 [4] Worker1 after await
05:23:25.610 [7] Worker2 after await
05:23:25.610 [6] Worker3 after await
05:23:25.610 [5] Worker4 after await
现在,如果我评论这句话
await task
并取消对以下行的注释
await Task.WhenAll(task)
,输出完全不同。所有延续都在同一个线程中运行,因此计算不是并行的。每次计算都是在前一次计算完成后开始的:
05:23:46.550 [1] Worker1 before await
05:23:46.575 [1] Worker2 before await
05:23:46.576 [1] Worker3 before await
05:23:46.576 [1] Worker4 before await
05:23:46.645 [4] Worker1 after await
05:23:47.648 [4] Worker2 after await
05:23:48.650 [4] Worker3 after await
05:23:49.651 [4] Worker4 after await
令人惊讶的是,只有当每个工人等待不同的包装器时,才会发生这种情况。如果我预先定义包装器:
var task = Task.WhenAll(Task.Delay(500));
…然后
await
在所有worker中执行相同的任务时,行为与第一种情况(异步延续)相同。
我的问题是:
为什么会发生这种情况?是什么导致同一任务的不同包装器的延续在同一线程中同步执行?
注:
用以下命令包装任务
Task.WhenAny
而不是
任务。When All
导致同样的奇怪行为。
另一个观察:
我原以为把包装纸包在里面
Task.Run
将使延续异步。但这并没有发生。以下行的延续仍然在同一线程中执行(同步)。
await Task.Run(async () => await Task.WhenAll(task));
澄清:
在上运行的Console应用程序中观察到上述差异。NET Core 3.0平台。上。NET Framework 4.8中,等待原始任务或任务包装器之间没有区别。在这两种情况下,延续都是在同一线程中同步执行的。