zoukankan      html  css  js  c++  java
  • C#版本的CPU性能测试

    本文不讲C#开发技巧,只测试同样的代码在不同CPU的机器上的运行速度。结果包括普通版本和并行版本的对比,方便大家选配电脑,对“性能”有个感性的认识。

    一. 测试原理

        字符串相关度计算是文本处理和数据挖掘中一个不可或缺的方法,例如论文查重等。Levenshtein Distance可以用来比较两个字符串的相似度,即两个字符串之间的“距离”。这个“距离”其实就是从源字符串变换到目标字符串需要进行的删除、插入和替换的次数。算法简图如下:

      字符串相似度比较Levenshtein <wbr>Distance

       有不少该算法的改进版本,可大幅度提升效率,不过这不是本文的目的。我们的目的就是看看该算法在不同的机器下到底能跑多快,再看并行优化后又能跑多快。该算法基本只对CPU性能敏感,很适合做测试。

       我们随机生成1000个1000长度的字符串,并比较字符串相关度。示例工程可在文末找到,由于需要并行计算,需要VS2010,.NET4.0支持。

      代码如下:

    View Code
    namespace SpeedTest
    {
        using System;
        using System.Diagnostics;
        using System.Text;
        using System.Threading.Tasks;
    
        internal class Program
        {
            #region Methods
    
            private static void Main(string[] args)
            {
                var  watch =new Stopwatch();
                const long count = 1000;
                const int length = 1000;
                string comparestring = StringDistance.GenerateRandomString(length);
                var strlist = new string[count];
                var steps = new int[count];
                // prepare string[] for comparison  
    
                Parallel.For(0, count, i => strlist[i] = StringDistance.GenerateRandomString(length));
    
                Console.WriteLine("已经生成了" + count + "个长度为" + length + "的字符串");
    
                watch.Start();
                for (int i = 0; i < count; i++)
                {
                    steps[i] = StringDistance.LevenshteinDistance(comparestring, strlist[i]);
                }
                watch.Stop();
                Console.WriteLine("完成非并行计算,耗时(ms)"+watch.ElapsedMilliseconds);
                Console.WriteLine("性能比" + 100000d/watch.ElapsedMilliseconds);
                watch.Reset();
                watch.Start();
                Parallel.For(
                    0, count, delegate(long i) { steps[i] = StringDistance.LevenshteinDistance(comparestring, strlist[i]); });
                watch.Stop();
                Console.WriteLine("完成并行计算,耗时(ms)" + watch.ElapsedMilliseconds);
                Console.WriteLine("性能比" + 100000d / watch.ElapsedMilliseconds);
                 Console.ReadKey();
            }
    
            #endregion
        }
    
        internal class StringDistance
        {
            #region Public Methods
    
            public static string GenerateRandomString(int length)
            {
                var r = new Random((int)DateTime.Now.Ticks);
                var sb = new StringBuilder(length);
                for (int i = 0; i < length; i++)
                {
                    int c = r.Next(97, 123);
                    sb.Append(Char.ConvertFromUtf32(c));
                }
                return sb.ToString();
            }
    
            public static int LevenshteinDistance(string str1, string str2)
            {
                var scratchDistanceMatrix = new int[str1.Length + 1,str2.Length + 1];
                // distance matrix contains one extra row and column for the seed values         
                for (int i = 0; i <= str1.Length; i++)
                {
                    scratchDistanceMatrix[i, 0] = i;
                }
                for (int j = 0; j <= str2.Length; j++)
                {
                    scratchDistanceMatrix[0, j] = j;
                }
                for (int i = 1; i <= str1.Length; i++)
                {
                    int str1Index = i - 1;
                    for (int j = 1; j <= str2.Length; j++)
                    {
                        int str2Index = j - 1;
                        int cost = (str1[str1Index] == str2[str2Index]) ? 0 : 1;
                        int deletion = (i == 0) ? 1 : scratchDistanceMatrix[i - 1, j] + 1;
                        int insertion = (j == 0) ? 1 : scratchDistanceMatrix[i, j - 1] + 1;
                        int substitution = (i == 0 || j == 0) ? cost : scratchDistanceMatrix[i - 1, j - 1] + cost;
                        scratchDistanceMatrix[i, j] = Math.Min(Math.Min(deletion, insertion), substitution);
                        // Check for Transposition  
                        if (i > 1 && j > 1 && (str1[str1Index] == str2[str2Index - 1]) &&
                            (str1[str1Index - 1] == str2[str2Index]))
                        {
                            scratchDistanceMatrix[i, j] = Math.Min(
                                scratchDistanceMatrix[i, j], scratchDistanceMatrix[i - 2, j - 2] + cost);
                        }
                    }
                }
                // Levenshtein distance is the bottom right element       
                return scratchDistanceMatrix[str1.Length, str2.Length];
            }
    
            #endregion
        }
    }

      废话不说,上测试结果。

       二.测试结果

         1. Debug,Debug直接运行,Release调试,Release直接运行的区别

          以上四种环境对应不同开发阶段的软件性能,对开发的性能调优有指导价值。

          电脑配置如下:

    image

    测试结果如下,数值为执行时间,单位为ms

    image

    image

        值得注意的是,在不同代码下四种环境的结果是很不相同的。一般情况下软件直接运行要比调试快很多。Release模式比Debug模式快几倍。但在这个示例下,直接运行和调试却没有特别明显的区别,希望大神能给予解答。

       另外,并行算法比普通的串行算法快了四倍。符合四核CPU的实际情况。

          2.不同CPU下的性能

       接下来,我们来看不同CPU下的性能区别。为简化测试,以下所有结果都采用Release运行模式。对比不同CPU在串行/并行下的速度区别。

      结果都是以执行时间ms表示的,值越小越好。

     

    古老电脑AMD QL-62 双核心 2.00GHz

    image

    难得找到AMD的笔记本电脑,该CPU已经停产很久了,三年前的CPU不负众望,成绩还不错,当然并行成绩比服务器慢了十几倍。

    笔记本T8100,双核2.4G

    image

    I3 2310 笔记本核心,双核,2.1GHz

    image

       虽然比T8100的频率低,但新一代酷睿I3还是完虐T8100的。

    桌面老牌酷睿E7300 双核心2.67GHz

    image

    回想06年底,能买到酷睿E6300是刚上高三的我最大的梦想,现在看来是在不敢恭维,并行速度和I7比差了四倍不止。这款当时很牛的桌面CPU连现在低端的笔记本CPU都不如。

     

    华硕笔记本UX31A, I5 3317U   双核双线程, @2.3GHz Auto OC

          image

      超级本的性能还是不错的,也体现出了双核的优势。在“节能模式”下,CPU不会自动睿频,只有1.7GHz。结果惨不忍睹。超级本一般情况下做开发足够了。

    第二代酷睿笔记本I5 2430 @ 2.3GHz

     

     

    image

    不得不说,标压笔记本的I5都可以完虐超低压的I7.  谁让超级本必须做到那么薄呢? 价格还死贵。如果考虑性能和性价比,还是选标压CPU吧。

    联想台式机 I3 2130 @3.4GHz

    image

    虽然是I3,但在串行下与同频的I7几乎无区别,当然由于是双核的,并行速度正好是串行的一半。

    I7 2600 四核八线程  3.4GHz

          image

    实在没有找到2600K的超频结果,就先用2600默频凑数吧,单核性能中规中矩。

    I5 2500K OC 4.2GHz 四核四线程

    image

    寝室台式机的跑分,看来频率是王道啊,在4.2G轻松秒杀I7 2600。

          服务器核心X5670  六核心 @2.93Ghz

     image

    服务器六核心CPU看似高端,但在这个程序下,还是无法与2600甚至2130抗衡,并行加速比4.66, 六核心有点小吃亏。

            服务器核心E5 2690 8核心,双CPU共16核心, 2.9GHz *2

    image 

      这几乎是我目前看到的最好结果, 该CPU在串行模式下就达到了11.657s的水平,并行加速比达到了可喜的7.32。可是与2500K这样的CPU不对等的是它的售价,一万三四够买10个2500K了。

     

    3. 测试总结和对比

      下图是不同CPU串行速度的对比图:

    image

       我们看到基本上同平台,同架构的CPU间,频率是王道。而当前I3新酷睿都可以干掉当年桌面的老酷睿经典,不得不说技术发展迅速。而服务器核心虽然核心多,甚至是双CPU,但频率一般,因此在这种普通应用下甚至抗不过桌面的I5 2500K。 能多核优化的程序还是占少数,大家能超就超一点吧,超频带来的性能提升真心不是一点点。

    下图是并行下速度对比图:

    image

    并行计算下,核的数量是王道!在非服务器核心上,加速比几乎就是CPU核心数。四核的速度就是比双核的快。在八核的顶级服务器CPU上,它的速度几乎是AMD QL-62的13倍!但若算是这台机器有双CPU16个核心的话,加速比和16还是差很多的。难道.NET并行库对多CPU支持不好?我怎么记得它可以支持最多64个CPU?

     

    三. 总结和源代码下载

           咱不是专业的硬件测评师,只是好奇之下跑了几个分数看了他们的性能而已,花了整整一晚上时间,因此若有不足之处还请海涵。

           总体来说,单核性能频率和架构决定一切,多核性能上核心数决定了加速比。 桌面级应用完全没必要买服务器的多核心(E3 1230这类除外)。大部分程序最多只对四核CPU做过优化。更多核心甚至双CPU会造成各种不兼容性问题,连游戏都打不了(嘿嘿),编程都卡。

           现在觉得,I5 2500K还是要比E3 1230性价比高很多,超频超出来的性能不是盖的。别担心寿命,它只会在需要的时候睿频到更高的频率,平时都是乖乖的二点几吉赫兹。而且非常简单!Enjoy it!

           程序并行的优势还是非常明显的,.NET的并行库可比Intel并行库方便多了(虽然效率不能比),但它可以很好的帮助你挖掘多核CPU的潜力。大家可以多学习一下.NET并行库。

           源代码下载

  • 相关阅读:
    现代软件工程 第一章 概论 第3题——韩婧
    现代软件工程 第一章 概论 第2题——韩婧
    小组成员邓琨、白文俊、张星星、韩婧
    UVa 10892 LCM的个数 (GCD和LCM 质因数分解)
    UVa 10780 幂和阶乘 求n!中某个因子的个数
    UVa 11859 除法游戏(Nim游戏,质因子)
    Codeforces 703C Chris and Road 二分、思考
    Codeforces 703D Mishka and Interesting sum 树状数组
    hdu 5795 A Simple Nim SG函数(多校)
    hdu 5793 A Boring Question 推公式(多校)
  • 原文地址:https://www.cnblogs.com/buptzym/p/2785408.html
Copyright © 2011-2022 走看看