简体   繁体   中英

async await vs parallel vs single thread performance

recently i've been working on an application that is supposed to be a thin layer on top of several services, this application is mainly doing mappings from different data format to a unified format (a lot of mappings). we use what i call "linq async" but I would like to see whether I can improve its performance.

I did a simple experiment like the following

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

I expect the senario2(linq async) should be more or less the same as senario3(parallel) as senario2 will create a lot of tasks and execute them concurrently. However, my simple experiment tells me im wrong. Senario2 is more or less the same as senario1. this confuses me a lot and I tried reading many related questions in stackoverflow but cannot find a satisfied answer. Most of the questions are talking about non-blocking UI, whereas my application is a backend service. Also I read about linq async will improve the throughput for a backend service under load, but from my experiment im not convinced. If it's not superior in performance for a single run, how can it improve the throughput under load??? Also i noticed the more item in the input array, the better performance i can get from parallel executing(scenario3). So I would like to ask my question here.

  1. is linq async not create a lot of tasks and execute them concurrently? why are they almost same as single thread?? Then what's the point of using them??
  2. for one call, parallel seems the fastest, how about under heavy load? which one is fastest and why??
  3. shall i rewrite linq async with parallel?? performance is important in my case
  4. or rather is there any flaws in my experiment?? should i do a I/O bound experiment?

Many thanks in advance.

The general benefit of async-await is not performance but responsiveness.

It's about releasing the current thread (the UI thread on client UIs, the thread pool thread on ASP.NET) when a blocking operation (usually, I/O) occurs.

Because every time the thread is released there's a context switch as well as when a thread is grabbed to continue the execution, asynchronous code has a bit of overhead and, thus, is less performing.

But because it promotes a better use of resources, the overall system might feel more performant just because it's more responsive.

When true parallelism is possible than, yes, the system is more performing.

In general, regarding performance, you should always measure your particular use case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM