“同步”异步方法的开销是多少?

时间:2013-05-21 04:36:25

标签: c# async-await

这是方法返回任务的基准,但在引擎盖下同步运行。

class MainClass
{
    public static async Task<int> UsingAsyncModifier()
    {
        return 10;
    }

    public static Task<int> UsingTaskCompletionSource()
    {
        TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
        tcs.SetResult(10);
        return tcs.Task;
    }

    public static Task<int> UsingTaskFromResult()
    {
        return Task.FromResult(10);
    }

    public static void Main(string[] args)
    {
        DateTime t = DateTime.Now;
        const int repeat = 10000; // Results volatile while repeat grows.
        Console.WriteLine("Repeat {0} times.", repeat);

        int j = 0;
        for (int i = 0; i < repeat; i++)
        {
            j += UsingAsyncModifier().Result;
        }
        Console.WriteLine("UsingAsyncModifier: {0}", DateTime.Now - t);
        t = DateTime.Now;

        for (int i = 0; i < repeat; i++)
        {
            j += UsingTaskCompletionSource().Result;
        }
        Console.WriteLine("UsingTaskCompletionSource: {0}", DateTime.Now - t);
        t = DateTime.Now;

        for (int i = 0; i < repeat; i++)
        {
            j += UsingTaskFromResult().Result;
        }
        Console.WriteLine("UsingTaskFromResult: {0}", DateTime.Now - t);
    }
}

输出(重复10,000 / 100,000 / 1000,000次):

Repeat 10000 times.
UsingAsyncModifier: 00:00:00.1043980
UsingTaskCompletionSource: 00:00:00.0095270
UsingTaskFromResult: 00:00:00.0089460

重复10,000次,UsingTaskFromResult比 UsingAsyncModifier 快10倍。

Repeat 100000 times.
UsingAsyncModifier: 00:00:00.1676000
UsingTaskCompletionSource: 00:00:00.0872020
UsingTaskFromResult: 00:00:00.0870180

重复100,000次,使用TaskFromResult比 UsingAsyncModifier 快2倍。

Repeat 1000000 times.
UsingAsyncModifier: 00:00:00.8458490
UsingTaskCompletionSource: 00:00:00.8870980
UsingTaskFromResult: 00:00:00.9027320

重复1,000,000次, UsingAsyncModifier 比UsingTaskFromResult快一点。

我认为,async修饰符刚刚创建了一个已完成的任务,类似于Task.FromResult()。但基准并不能证明我的想法。 为什么呢?

1 个答案:

答案 0 :(得分:2)

虽然我使用DateTime看到了相似的结果,但使用Stopwatch进行时间测量表明,使用UsingAsyncModifier()的迭代所需的时间比使用UsingTaskCompletionSource()长2倍或者UsingTaskFromResult(),两者都显示相等的持续时间),即使有1 000 000次迭代

这是输出:

Repeat 1000000 times.
UsingAsyncModifier: 5458
UsingTaskCompletionSource: 2838
UsingTaskFromResult: 2556

使用Stopwatch

代码
class Program
{
     public static async Task<int> UsingAsyncModifier()
    {
        return 10;
    }

    public static Task<int> UsingTaskCompletionSource()
    {
        TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
        tcs.SetResult(10);
        return tcs.Task;
    }
    public static Task<int> UsingTaskFromResult()
    {
        return TaskEx.FromResult(10);
    }
    static void Main(string[] args)
    {
      //DateTime t = DateTime.Now;
      Stopwatch timer = new Stopwatch();
      const int repeat = 1000*1000; // Results volatile while repeat grows.
      Console.WriteLine("Repeat {0} times.", repeat);

        int j = 0;
        //DateTime t = DateTime.Now;
        timer.Start();
        for (int i = 0; i < repeat; i++)
        {
            j += UsingAsyncModifier().Result;
        }
        timer.Stop();
        Console.WriteLine("UsingAsyncModifier: {0}"
                          , timer.ElapsedMilliseconds);
        //t = DateTime.Now;
        timer.Reset();

        j = 0;

        timer.Start();
        for (int i = 0; i < repeat; i++)
        {
            j += UsingTaskCompletionSource().Result;
        }
        timer.Stop();
        Console.WriteLine("UsingTaskCompletionSource: {0}"
                           , timer.ElapsedMilliseconds);
        //t = DateTime.Now;
        timer.Reset();
        j = 0;
        timer.Start();
        for (int i = 0; i < repeat; i++)
        {
          j += UsingTaskFromResult().Result;
        }
        timer.Stop();
        Console.WriteLine("UsingTaskFromResult: {0}"
                          , timer.ElapsedMilliseconds);

        Console.ReadLine();
    }
}

Stephen Toub在他的“Async Performance: Understanding the Costs of Async and Await”中解释道:

  

使用同步代码时,具有空体的方法是   几乎是免费的。异步方法不是这种情况

阅读更多详情