Why is await async so slow?

.net-4.5, async-await, c#, multithreading, performance

Solution

Your benchmark has a couple of flaws:

- You are timing the first run which includes initialization time (loading `class Task`, JIT-compilation etc.)

- You are using `DateTime.Now`, which is too inaccurate for timings in the millisecond range. You'll need to use `StopWatch`

With these two issues fixed; I get the following benchmark results:

Regular Sum:  499946 in 00:00:00.0047378
Async Sum:    499946 in 00:00:00.0016994
Threaded Sum: 499946 in 00:00:00.0026898

Async now comes out as the fastest solution, taking less than 2ms.

This is the next problem: timing something as fast as 2ms is extremely unreliable; your thread can get paused for longer than that if some other process is using the CPU in the background. You should average the results over several thousands of benchmark runs.

Also, what's going on with your number of core detection? My quad-core is using a chunk size of 333334 which allows only 3 threads to run.

Problem

I finally got VS2012 and got a simple demo up and working to check out the potential performance boost of async and await, but to my dismay it is slower! Its possible I'm doing something wrong, but maybe you can help me out. (I also added a simple Threaded solution, and that runs faster as expected) My code uses a class to sum an array, based on the number of cores on your system (-1) Mine had 4 cores, so I saw about a 2x speed up (2.5 threads) for threading, but a 2x slow down for the same thing but with async/await. Code: (Note you will need to added the reference to `System.Management` to get the core detector working) ``` using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Management; using System.Diagnostics; namespace AsyncSum { class Program { static string Results = ""; static void Main(string[] args) { Task t = Run(); t.Wait(); Console.WriteLine(Results); Console.ReadKey(); } static async Task Run() { Random random = new Random(); int[] huge = new int[1000000]; for (int i = 0; i < huge.Length; i++) { huge[i] = random.Next(2); } ArraySum summer = new ArraySum(huge); Stopwatch sw = new Stopwatch(); sw.Restart(); long tSum = summer.Sum(); for (int i = 0; i < 100; i++) { tSum = summer.Sum(); } long tticks = sw.ElapsedTicks / 100; long aSum = await summer.SumAsync(); sw.Restart(); for (int i = 0; i < 100; i++) { aSum = await summer.SumAsync(); } long aticks = sw.ElapsedTicks / 100; long dSum = summer.SumThreaded(); sw.Restart(); for (int i = 0; i < 100; i++) { dSum = summer.SumThreaded(); } long dticks = sw.ElapsedTicks / 100; long pSum = summer.SumParallel(); sw.Restart(); for (int i = 0; i < 100; i++) { pSum = summer.SumParallel(); } long pticks = sw.ElapsedTicks / 100; Program.Results += String.Format("Regular Sum: {0} in {1} ticks\n", tSum, tticks); Program.Results += String.Format("Async Sum: {0} in {1} ticks\n", aSum, aticks); Program.Results += String.Format("Threaded Sum: {0} in {1} ticks\n", dSum, dticks); Program.Results += String.Format("Parallel Sum: {0} in {1} ticks\n", pSum, pticks); } } class ArraySum { int[] Data; int ChunkSize = 1000; int cores = 1; public ArraySum(int[] data) { Data = data; cores = 0; foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get()) { cores += int.Parse(item["NumberOfCores"].ToString()); } cores--; if (cores < 1) cores = 1; ChunkSize = Data.Length / cores + 1; } public long Sum() { long sum = 0; for (int i = 0; i < Data.Length; i++) { sum += Data[i]; } return sum; } public async Task<long> SumAsync() { Task<long>[] psums = new Task<long>[cores]; for (int i = 0; i < psums.Length; i++) { int start = i * ChunkSize; int end = start + ChunkSize; psums[i] = Task.Run<long>(() => { long asum = 0; for (int a = start; a < end && a < Data.Length; a++) { asum += Data[a]; } return asum; }); } long sum = 0; for (int i = 0; i < psums.Length; i++) { sum += await psums[i]; } return sum; } public long SumThreaded() { long sum = 0; Thread[] threads = new Thread[cores]; long[] buckets = new long[cores]; for (int i = 0; i < cores; i++) { int start = i * ChunkSize; int end = start + ChunkSize; int bucket = i; threads[i] = new Thread(new ThreadStart(() => { long asum = 0; for (int a = start; a < end && a < Data.Length; a++) { asum += Data[a]; } buckets[bucket] = asum; })); threads[i].Start(); } for (int i = 0; i < cores; i++) { threads[i].Join(); sum += buckets[i]; } return sum; } public long SumParallel() { long sum = 0; long[] buckets = new long[cores]; ParallelLoopResult lr = Parallel.For(0, cores, new Action<int>((i) => { int start = i * ChunkSize; int end = start + ChunkSize; int bucket = i; long asum = 0; for (int a = start; a < end && a < Data.Length; a++) { asum += Data[a]; } buckets[bucket] = asum; })); for (int i = 0; i < cores; i++) { sum += buckets[i]; } return sum; } } } ``` Any thoughts? Am I doing async/await wrong? I'll be happy to try any suggestions.

Original source