1. 程式人生 > >span之高效能字串操作實測

span之高效能字串操作實測

span<T>之高效能字串操作實測

   .net中的字串操作效能問題由來已久,幸運的是微軟推出了span<T>高效能指標操作封裝工具類。這個類到底有多高的效能呢?網上傳言反正很高,但是實際上在網上很難找到合適的測試例項,這讓本人實在無力吐槽。經不住高效能這三個字的誘惑,本人還是瞭解了一番後做了幾個簡單樣例來測試一番,下面列出幾種字串常見操作的測試程式碼及其執行結果。

一、String.Index 測試

 

1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     str.IndexOf(subStr);
6                 }
7             });
8 
9             Console.WriteLine($"string.IndexOf {count} 次用時:{t1} 毫秒");

 

 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var subStrSpan = subStr.AsSpan();
 6 
 7                 for (int i = 0; i < count; i++)
 8                 {
 9                     strSpan.IndexOf(subStrSpan);
10                 }
11             });
12 
13             Console.WriteLine($"Span<T>.IndexOf {count} 次用時:{t2} 毫秒");

 

 

二、String.Substring 測試

 

1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     str.Substring(0, str.IndexOf(subStr));
6                 }
7             });
8 
9             Console.WriteLine($"String.Substring {count} 次用時:{t1} 毫秒");

 

 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var subStrSpan = subStr.AsSpan();
 6 
 7                 var index = strSpan.IndexOf(subStrSpan);
 8 
 9                 for (int i = 0; i < count; i++)
10                 {
11                     strSpan.Slice(0, strSpan.IndexOf(subStrSpan));
12                 }
13             });

 

三、String.Split 測試

 

1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     var arr = str.Split(new string[] { splitStr }, StringSplitOptions.None);
6                 }
7             });
8 
9             Console.WriteLine($"String.Split {count} 次用時:{t1} 毫秒");
 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var splitSapn = splitStr.AsSpan();
 6 
 7                 int m = 0, n = 0;
 8 
 9                 for (int i = 0; i < count; i++)
10                 {
11                     List<string> arr = new List<string>();
12 
13                     while (true)
14                     {
15                         m = n;
16                         n = strSpan.IndexOf(splitSapn);
17                         if (n > -1)
18                         {
19                             arr.Add(strSpan.Slice(0, n).ToString());
20                             strSpan = strSpan.Slice(n + splitSapn.Length);
21                         }
22                         else
23                         {
24                             break;
25                         }
26                     }
27 
28                 }
29             });
30 
31             Console.WriteLine($"Span<T>.Split {count} 次用時:{t2} 毫秒");

 

四、String.Replace 測試

 

1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     str.Replace(splitStr, replaceStr);
6                 }
7             });
8 
9             Console.WriteLine($"String.Replace {count} 次用時:{t1} 毫秒");

 

 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var splitSapn = splitStr.AsSpan();
 6 
 7                 int m = 0, n = 0;
 8 
 9                 for (int i = 0; i < count; i++)
10                 {
11                     List<string> arr = new List<string>();
12 
13                     while (true)
14                     {
15                         m = n;
16                         n = strSpan.IndexOf(splitSapn);
17                         if (n > -1)
18                         {
19                             arr.Add(strSpan.Slice(0, n).ToString());
20                             strSpan = strSpan.Slice(n + splitSapn.Length);
21                         }
22                         else
23                         {
24                             break;
25                         }
26                     }
27                     string.Join(replaceStr, arr);
28                 }
29             });
30 
31             Console.WriteLine($"Span<T>.Replace {count} 次用時:{t2} 毫秒");

 

 

  怎麼樣,經過上面的測試,是不是覺的Span<T>確實是名不虛傳?的確,在上面幾個常見場景中,Span<T>的高效能確實不同凡響,差不多是10倍的效能優勢!看到這裡,小夥伴們是不是覺的字串操作全改成Span<T>就行了?那下面的兩個測試會讓大家看清現實,在String.Contains中表現還不如原生的。

一、String.Contains 測試

 

1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     str.Contains(subStr);
6                 }
7             });
8 
9             Console.WriteLine($"string.Contains {count} 次用時:{t1} 毫秒");

 

 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var subStrSpan = subStr.AsSpan();
 6 
 7                 for (int i = 0; i < count; i++)
 8                 {
 9                     strSpan.Contains(subStrSpan, StringComparison.CurrentCulture);
10                 }
11             });
12 
13             Console.WriteLine($"Span<T>.Contains {count} 次用時:{t2} 毫秒");

 

  仔細一看,不對啊,Span<T>的Contains裡面有其它的大小寫和語言相關的判斷啊。好,那再換一個原生方法對比測試一下。

二、String.Compare 測試

 

1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     string.Compare(str, subStr, true);
6                 }
7             });
8 
9             Console.WriteLine($"string.Compare {count} 次用時:{t1} 毫秒");

 

 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var subStrSpan = subStr.AsSpan();
 6 
 7                 for (int i = 0; i < count; i++)
 8                 {
 9                     strSpan.Contains(subStrSpan, StringComparison.CurrentCultureIgnoreCase);
10                 }
11             });
12 
13             Console.WriteLine($"Span<T>.Contains {count} 次用時:{t2} 毫秒");

 

  還是被反殺了,這說明Span<T>的這個Contains方法可能真的只能在某些地方才能用,不然效能反而會有所下降。

       如果對上述感興趣,可以點選這裡下載測試原始碼,更多請點選左下角的推薦,謝謝~