[C#].NET中字符串的 ToLower,ToUpper,ToLowerInvariant,ToUpperInvariant 性能測試及分析


我最近在研讀《CLR via C#》,其中有一個章節講String類型,Jeffrey說當進行不區分大小寫的字符串對比時,應當盡量多的使用ToUpperInvariant,因為一方面CLR對轉換為大寫的操作進行了專門的優化,使其性能更加卓越;另一方面ToUpperInvariant和ToLowerInvariant忽略了對語言文化的處理,因此性能比ToUpper和ToLower要快得多。

從理論層面上來講,這應該是正確的。但是究竟能快多少呢?或者說這種性能提升值不值得我們付出專門的精力來關注呢?

我們下面就進行一個測試,看看它們究竟能對性能產生多大影響。

首先,我實例化了一個 char 類型數組,並使用 Char Code 在 0 到 133 之間的隨機字符填滿,我們就得到了一個隨機的測試用例,其中包含半角符號、小寫英文字母和大寫英文字母。

然后我要分別測試 Char 類型的四個靜態函數和 String 類型的四個實例函數,我猜測 String 類型中的實例函數實際上也是通過 Char 類型中相對應的靜態函數實現的。

為了避免CLR的內存優化對測試結果產生影響,每執行一項測試之前,都將在堆中創建新的示例,並從測試用例中復制成員。

除此之外,為了盡量保證測試結果的正確性,我將循環執行並記錄測試代碼 N 次,之后取它們的去權平均值。

=====================我是分割線=====================

下面是測試代碼:

填充數組:

 1 static void Fill()
 2  {
 3     //實例化一個容納10000個字符的數組
 4     letters = new char[maxElementsCount];
 5     //填充數組
 6     for (int i = 0; i < maxElementsCount; i++)
 7     {
 8         var charcode = R.Next(0, 133);
 9         letters[i] = Convert.ToChar(charcode);
10     }
11 }

 

執行 Char 靜態方法測試的執行函數:

 1  static double Invoke(Action<char[]> func,string testname)
 2 {
 3     char[] source = new char[maxElementsCount];
 4     letters.CopyTo(source, 0);
 5     DateTime start = DateTime.Now; //當前時間
 6     DateTime end = DateTime.Now;
 7     Console.WriteLine("開始測試 "+ testname + " [開始時間:" + start.ToString() + "]");
 8     func(source);
 9     end = DateTime.Now;
10     var during = (end - start).TotalMilliseconds;
11     Console.WriteLine("測試 " + testname + " 完成,耗時" + during + "毫秒[結束時間:" + end.ToString() + "]");
12     return during;
13 }

 

執行 String 實例方法的執行函數:

 1 static double InvokeString(Action<string> func, string testname)
 2 {
 3     string source = new string(letters);
 4     DateTime start = DateTime.Now; //當前時間
 5     DateTime end = DateTime.Now;
 6     Console.WriteLine("開始測試 " + testname + " [開始時間:" + start.ToString() + "]");
 7     func(source);
 8     end = DateTime.Now;
 9     var during = (end - start).TotalMilliseconds;
10     Console.WriteLine("測試 " + testname + " 完成,耗時" + during + "毫秒[結束時間:" + end.ToString() + "]");
11     return during;
12 }

 

測試方法:

 1 static void Run(int maxElementsCount)
 2 {
 3     Fill();
 4 
 5     char_tolower.Add(Invoke(s =>
 6     {
 7         for (int i = 0; i < s.Length; i++)
 8         {
 9             char.ToLower(s[i]);
10         }
11     }, "Char.ToLower"));
12 
13     char_toupper.Add(Invoke(s =>
14     {
15         for (int i = 0; i < s.Length; i++)
16         {
17             char.ToUpper(s[i]);
18         }
19     }, "Char.ToUpper"));
20 
21     char_tolowerinvariant.Add(Invoke(s =>
22     {
23         for (int i = 0; i < s.Length; i++)
24         {
25             char.ToLowerInvariant(s[i]);
26         }
27     }, "Char.ToLowerInvariant"));
28 
29     char_toupperinvariant.Add(Invoke(s =>
30     {
31         for (int i = 0; i < s.Length; i++)
32         {
33             char.ToUpperInvariant(s[i]);
34         }
35     }, "Char.ToUpperInvariant"));
36 
37     string_tolower.Add(InvokeString(s =>
38     {
39         s.ToLower();
40     }, "String.ToLower"));
41 
42     string_toupper.Add(InvokeString(s =>
43     {
44         s.ToUpper();
45     }, "String.ToUpper"));
46 
47     string_tolowerinvariant.Add(InvokeString(s =>
48     {
49         s.ToLowerInvariant();
50     }, "String.ToLowerInvariant"));
51 
52     string_toupperinvariant.Add(InvokeString(s =>
53     {
54         s.ToUpperInvariant();
55     }, "String.ToUpperInvariant"));
56 }

 以下是循環執行1000次的去權平均數:

 從結果中我們可以看出,ToLowerInvariant 和 ToUpperInvariant 因為忽略的語言信息,性能的確是比關注語言信息的 ToLower 和 ToUpper 要快一些。但是Char.ToUpper的性能比Char.ToLower的性能竟然還要差,這可能是由於隨機的測試數據不夠隨機造成的。

此外,還可以得出 String 類型的四個實例函數並非通過 Char 中的靜態函數實現的 , 這應該是因為.NET CLR 中定義的 String 是一個單獨的基元類型,而並非是 Char 數組 , 因此經過了單獨的實現,並且性能明顯要好過 Char 的數組。

但是我這里用的測試數據是一個長達 100萬 字的字符串,在這種情況下的性能損失不足0.1毫秒,實在是不值一提。我測試用的電腦是 i5 4代處理器,相信在計算能力更強的處理器上,這個數值將被無限的縮小。因此我們在實際開發中幾乎不需要特別關注應當用哪個方法,特別是如果在做國際化的應用時,ToLowerInvariant 和 ToUpperInvariant 雖然能夠帶來性能的提升,但是也可能導致隱形BUG,並不值得推廣。此外,在開發中我們應當盡量少的使用 Char 類型,一個 Char 類型對象要單獨占用一個棧內存地址,且只能存儲一個字符,實在是太不合算。


免責聲明!

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



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