为什么异步异步/线程运行?

时间:2019-02-18 13:42:56

标签: c# async-await

我正在关注一篇文章,该文章显示异步/任务不是线程。 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}");
            }
        }

    }
}

1 个答案:

答案 0 :(得分:4)

此处的关键是缺少同步上下文。链接的文章是WPF应用程序,在其Main / UI线程上具有同步上下文。您创建的控制台应用程序根本没有一个。

其结果是该文章说的是

  

当您“等待”异步任务时,方法的其余部分将在与开始时相同的上下文中继续运行。在WPF中,该上下文是UI线程。

这不适用于您的示例。在Task.Delay之后,您的代码将在线程池线程上恢复。这样您的所有3个任务都可以并行运行。

这与文章稍后使用ConfigureAwait(false)时的情况非常相似,这会阻止在捕获的同步上下文中恢复执行。