我正在关注一篇文章,该文章显示异步/任务不是线程。 https://blogs.msdn.microsoft.com/benwilli/2015/09/10/tasks-are-still-not-threads-and-async-is-not-parallel/
在他们的示例中,他们通过创建3个任务来构建一个异步调用,以显示此操作,每个任务运行一个暂停几秒钟的循环。我已经在控制台(标记为STAThread)应用程序中重新创建了它。
但是,在我下面的代码中,我期望在本文所述的两个示例中,它花费相同的15秒(每个任务5秒)。但是,第二个步骤仅花费5秒,因此同时运行所有3个步骤,我的第二个示例需要5秒钟才能完成。原始文章花了5秒钟,但我将其更改为1秒延迟,以使其更加明显。
任何人都可以解释发生了什么以及为什么它似乎是线程化的吗?
class AsyncTest
{
Stopwatch sw = new Stopwatch();
internal void Tests()
{
DoASynchronous1();
//update below to be DoAsync2 and repeat
}
private void DoASynchronous1()
{
sw.Restart();
var start = sw.ElapsedMilliseconds;
Console.WriteLine($"\nStarting ASync Test, interval 1000ms");
Task a=DoASync1("A",1000); //change these to 2
Task b=DoASync1("B",1000);
Task c=DoASync1("C",1000);
Task.WaitAll(a, b, c);
sw.Stop();
Console.WriteLine($"Ended Sync Test. Took {(sw.ElapsedMilliseconds - start)} mseconds");
Console.ReadKey();
}
//this runs synchronously showing async is not threaded
//this takes 15 seconds
private async Task DoASync1(string v, int delay)
{
//loop for 5 seconds
for (int i = 1; i <= 5; i++)
{
await Task.Delay(0); //or simply omit
var startTime = sw.ElapsedMilliseconds;
while (sw.ElapsedMilliseconds < startTime+(delay)) { }
Console.WriteLine($"{v}:{i}");
}
}
//this is taking 5 seconds
private async Task DoASync2(string v, int delay)
{
//loop for 5 seconds
for (int i = 1; i <= 5; i++)
{
await Task.Delay(100);
var startTime = sw.ElapsedMilliseconds;
while (sw.ElapsedMilliseconds < startTime + delay) { }
var endtime = sw.ElapsedMilliseconds;
Console.WriteLine($"{v}:{endtime}");
}
}
}
}
答案 0 :(得分:4)
此处的关键是缺少同步上下文。链接的文章是WPF应用程序,在其Main / UI线程上具有同步上下文。您创建的控制台应用程序根本没有一个。
其结果是该文章说的是
当您“等待”异步任务时,方法的其余部分将在与开始时相同的上下文中继续运行。在WPF中,该上下文是UI线程。
这不适用于您的示例。在Task.Delay
之后,您的代码将在线程池线程上恢复。这样您的所有3个任务都可以并行运行。
这与文章稍后使用ConfigureAwait(false)
时的情况非常相似,这会阻止在捕获的同步上下文中恢复执行。