为什么 await async 这么慢? [英] Why is await async so slow?

查看:50
本文介绍了为什么 await async 这么慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我终于得到了 VS2012 并得到了一个简单的演示,并努力检查 async 和 await 的潜在性能提升,但令我失望的是它变慢了!可能我做错了什么,但也许你可以帮助我.(我还添加了一个简单的线程解决方案,它按预期运行得更快)

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)

我的代码使用一个类根据系统上的内核数对数组求和 (-1) 我的有 4 个内核,所以我看到线程处理速度提高了大约 2 倍(2.5 个线程),但速度降低了 2 倍同样的事情,但使用 async/await.

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.

代码:(请注意,您需要添加对System.Management 的引用才能使核心检测器工作)

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
", tSum, tticks);
            Program.Results += String.Format("Async Sum: {0} in {1} ticks
", aSum, aticks);
            Program.Results += String.Format("Threaded Sum: {0} in {1} ticks
", dSum, dticks);
            Program.Results += String.Format("Parallel Sum: {0} in {1} ticks
", 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;
        }
    }
}

有什么想法吗?我做 async/await 错了吗?我很乐意尝试任何建议.

Any thoughts? Am I doing async/await wrong? I'll be happy to try any suggestions.

推荐答案

您的基准测试有几个缺陷:

Your benchmark has a couple of flaws:

  • 您正在为第一次运行计时,其中包括初始化时间(加载 class Task、JIT 编译等)
  • 您正在使用 DateTime.Now,这对于毫秒范围内的计时来说太不准确了.您需要使用 StopWatch
  • 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

异步现在是最快的解决方案,耗时不到 2 毫秒.

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

这是下一个问题:2ms 的时间非常不可靠;如果其他进程在后台使用 CPU,您的线程可能会暂停更长的时间.您应该对数千次基准测试的结果进行平均.

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.

另外,你的核心检测数量是怎么回事?我的四核使用 333334 的块大小,它只允许运行 3 个线程.

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.

这篇关于为什么 await async 这么慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆