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並行庫。

       源代碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM