async await vs parallel vs single thread performance

时间:2017-09-18 06:12:26

标签: c# asynchronous async-await task-parallel-library

最近我一直致力于一个应用程序,它应该是几个服务之上的薄层,这个应用程序主要是从不同的数据格式到统一格式(很多映射)的映射。我们使用我称之为“linq async”但我想看看我是否可以提高其性能。

我做了一个简单的实验,如下面的

using System;
using System.Collections.Async;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int max = 100;
            int[] input = Enumerable.Range(1, max).ToArray();
            Work w = new Work();

            // senario 1
            sw.Restart();
            var result1 = input.Select(x => w.LongHoursWork(x)).ToArray();
            sw.Stop();
            Console.WriteLine($"One Thread: {sw.ElapsedMilliseconds}");

            // senario 2
            sw.Restart();
            var result2 = MainAsync(input, w).GetAwaiter().GetResult();
            sw.Stop();
            Console.WriteLine($"Linq async: {sw.ElapsedMilliseconds}");

            // senario 3
            sw.Restart();
            var result3 = input.AsParallel().Select(x => w.LongHoursWork(x)).ToArray();
            sw.Stop();
            Console.WriteLine($"Parallel: {sw.ElapsedMilliseconds}");

            // check result
            for (int i = 0; i < max; i++)
            {
                if(result1[i] == result2[i] && result2[i] == result3[i])// && result4.Contains(result1[i]))
                    continue;

                throw new ArgumentNullException();
            }

            Console.ReadKey();
        }


        static async Task<string[]> MainAsync(int[] input, Work work)
        { 
            var result = await Task.WhenAll(input.Select(async x => await work.LongHoursWorkAsync(x)));
            return result;
        }
    }

    public class Work
    {
        public string LongHoursWork(int i)
        {
            for (int ix = 0; ix < 100000; ix++)
            {
                i += ix;
            }
            return i.ToString();
        }

        public async Task<string> LongHoursWorkAsync(int i)
        {
            return await Task.FromResult(LongHoursWork(i));
        }
    }
}

//execution result:
//One Thread: 88
//Linq async: 97
//Parallel: 59 

// if i change the input array to 600(similar to what i have in production 
// environment)
// execution result:
// One Thread: 347
// Linq async: 292
// Parallel: 101

我希望senario2(linq async)应该与senario3(并行)大致相同,因为senario2将创建大量任务并同时执行它们。但是,我的简单实验告诉我错误。 Senario2与senario1或多或少相同。这让我很困惑,我试着读书 stackoverflow中的许多相关问题但无法找到满意的答案。大多数问题都是关于非阻塞UI,而我的应用程序是后端服务。另外我读到关于linq async将提高负载下后端服务的吞吐量,但是从我的实验我不相信。如果单次运行的性能不高,它怎样才能提高负载下的吞吐量?另外我注意到输入数组中的项目越多,我就能从并行执行中获得更好的性能(scenario3)。所以我想在这里提出我的问题。

  1. 是linq async不会创建很多任务并同时执行它们?为什么它们几乎与单线程相同?那么使用它们有什么意义?
  2. 对于一个电话,并行似乎最快,在重负载下如何?哪一个最快,为什么??
  3. 我应该用并行重写linq异步吗?在我的案例中,表现很重要
  4. 或者更确切地说,我的实验中有任何缺陷?我应该进行I / O绑定实验吗?
  5. 非常感谢提前。

1 个答案:

答案 0 :(得分:0)

async-await的一般好处不是表现而是响应能力。

当发生阻塞操作(通常是I / O)时,它是关于释放当前线程(客户端UI上的UI线程,ASP.NET上的线程池线程)。

因为每次释放线程时都会有一个上下文切换以及当一个线程被抓取以继续执行时,异步代码会产生一些开销,因此性能较差。

但是因为它促进了对资源的更好利用,整个系统可能会因为响应速度更快而感觉更高效。

当真正的并行性可行时,是的,系统的性能更高。

一般而言,关于性能,您应该始终测量您的特定用例。