为什么等待任务需要比返回任务花费更长的时间

时间:2016-02-09 13:08:39

标签: c# .net multithreading asynchronous async-await

我做了一个有趣的观察,我想完全理解。

最简单的解释方法是使用这个小样本控制台应用程序捕获它:

namespace AsyncAwaitTestApp
{
    using System;
    using System.Diagnostics;
    using System.Threading.Tasks;

    class Program
    {
        static void Main(string[] args)
        {
            var timer = new Stopwatch();

            // First Run:
            // -------------------------

            Console.WriteLine("Running GiveMeATask in parallel...");
            timer.Start();

            Parallel.For(0, 500, (i) =>
            {
                SillyClass.GiveMeATask().Wait();
            });

            timer.Stop();
            Console.WriteLine($"GiveMeATask run completed. Total time: {timer.Elapsed.TotalSeconds} seconds.");

            // Second Run:
            // -------------------------

            Console.WriteLine("-------------------------------");
            Console.WriteLine("Running AwaitATask in parallel...");
            timer.Restart();

            Parallel.For(0, 500, (i) =>
            {
                SillyClass.AwaitATask().Wait();
            });

            timer.Stop();
            Console.WriteLine($"AwaitATask run completed. Total time: {timer.Elapsed.TotalSeconds} seconds.");

            Console.ReadLine();
        }
    }

    public class SillyClass
    {
        public static TimeSpan SomeTime = TimeSpan.FromSeconds(3);

        public static Task GiveMeATask()
        {
            return Task.Delay(SomeTime);
        }

        public static async Task AwaitATask()
        {
            await Task.Delay(SomeTime);
        }
    }
}

它也可以Gist

SillyClass有两种方法都返回Task。在这两种方法中,我有3秒的Task.Delay来模拟昂贵的网络或IO绑定操作。

第一种方法GiveMeATask只是从Task.Delay返回任务。第二种方法AwaitATask等待Task.Delayasync / await个关键字。

Parallel.For调用这两个方法来模拟并发调用。

我觉得有趣的是,无论我重复多少次,第一次运行总是花费大约两倍的时间,而不是重复次数:

Output from console application

据我所知,async / await模式必须捕获同步上下文,这会增加一些开销,但如果这是原因我会感到惊讶吗?

我也理解在某些应用程序中,例如WPF应用程序或只有1个线程可以访问UI / Request上下文的ASP.NET应用程序,同步阻塞.Wait()会导致死锁,但事实并非如此对于控制台应用程序,显然我没有死锁,因为两个运行完全正常。

所以我显然不理解上述情况的全貌,并希望有人能够对此有所了解?

0 个答案:

没有答案