只有累積,沒有奇蹟

2022年11月15日 星期二

[NETCore] 動態 String 字串相加效能比較

前言
在前一篇 [.NETCore] String 字串相加效能比較 對於 C# string 的應用做了一些測試,得到在使用固定字串相加時使用 string 效能反而比 stringBuilder 來的好,在 string  有多種應用情境因此這篇就在針對另一種使用情境針對 string 動態文字相加做比較若有問題或是錯誤的地方歡迎各位給予指導及討論

測試代碼 
測試方式同樣以  BenchmarkDotNet  套件協助進行測試,對此套件有興趣可以參考介紹的文章 [.NETCore] 使用 BenchmarkDotNet 測試程式碼效能,上一篇介紹是使用固定字串相加做測試,這一篇則是在每一個測試方法中跑一個 for 迴圈將結果相加起來,同樣的測試 C# 中 string、stringBuilder、string.Format、Interpolation、string.Concat、string.Join 等字串相加的方法,BenchmarkDotnet 使用上相當容易,直接透過 BenchmarkRunner.Run<T> 靜態方法將要測試的類別帶入 T 即可,測試 Framework 希望得知動態字串在 .NET Framework 與 .NET Core 效能表現,因此在測試類別上加上  ClrJob,CoreJob  ,除了速度之外對於 Memory 以及 GC 的使用量也是使用上要考量的重點之一,可以加上  MemoryDiagnoser  觀察記憶體與 GC 的數據,代碼如下 
  1. namespace benchmarkLab
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. var summary = BenchmarkRunner.Run<stringTestBenchmark>();
  8. Console.ReadKey();
  9. }
  10. }
  11.  
  12. [MemoryDiagnoser]
  13. [ClrJob,CoreJob]
  14. public class stringTestBenchmark
  15. {
  16. StringBuilder _sb = new StringBuilder();
  17. // 測試代碼
  18. }
  19. }
使用 Benchmark 測試數據需要在方法上加上   Benchmark  attribute,使用 string 的相加測試的代碼如下
  1. [Benchmark]
  2. public void Normal()
  3. {
  4. string s = string.Empty;
  5. for (int i = 0; i < 10; i++)
  6. {
  7. s += i.ToString();
  8. }
  9. }
使用 stringBuilder 的相加測試的代碼如下
  1. [Benchmark]
  2. public void StringBuilder()
  3. {
  4. StringBuilder sb = new StringBuilder();
  5. for (int i = 0; i < 10; i++)
  6. {
  7. sb.Append(i.ToString());
  8. }
  9. string s = sb.ToString();
  10. }
另外一種使用 stringBuilder 的方式,將其宣告為區域變數使用前先 clear (很少看到有人這樣使用,但想測試看看在此應用情境速度是否會提升),測試的代碼如下
  1. [Benchmark]
  2. public void StringBuilderClear()
  3. {
  4. _sb.Clear();
  5. for (int i = 0; i < 10; i++)
  6. {
  7. _sb.Append(i.ToString());
  8. }
  9. string s = _sb.ToString();
  10. }
使用 string.Format,測試的代碼如下
  1. [Benchmark]
  2. public void Format()
  3. {
  4. string s = string.Empty;
  5. for (int i = 0; i < 10; i++)
  6. {
  7. s = string.Format("{0}{1}", s, i.ToString());
  8. }
  9. }
使用 C# 6.0 提供的新語法 Interpolation,測試的代碼如下
  1. [Benchmark]
  2. public void Interpolation()
  3. {
  4. string s = string.Empty;
  5. for (int i = 0; i < 10; i++)
  6. {
  7. s = $"{s}{i.ToString()}";
  8. }
  9. }
使用 string.Concat,測試的代碼如下
  1. [Benchmark]
  2. public void Concat()
  3. {
  4. string s = string.Empty;
  5. for (int i = 0; i < 10; i++)
  6. {
  7. s = string.Concat(s, i.ToString());
  8. }
  9. }
使用 string.Join,測試的代碼如下
  1. [Benchmark]
  2. public void Join()
  3. {
  4. string s = string.Empty;
  5. for (int i = 0; i < 10; i++)
  6. {
  7. s += string.Join(s, i.ToString());
  8. }
  9. }
好的,完成了測試代碼接著將專案設定為 Release mode,按下 F5 進行測試,可以看到執行 Console 一開始會說明 BenchmarkDotnet 將會進行 14 項任務 (2 Framework * 7 種方法) 的測試,測試時間會根據你要測試的項目多寡而不同,以本次測試來說在小弟電腦大約12-15 分鐘左右
測試完成後,會產生測試報各路徑在  release\BenchmarkDotNet.Artifacts\results  目錄底下
測試報告最上方為測試主機的硬體資訊,小弟筆電為 Intel Core i7-8550、16 G,Windows 10 環境,也會列出測試的 Framework 相關資訊,像是測試時是在 .NET Framework 4.7 與 .NET Core 2.2 進行測試,下方為在 string 中測試動態字串相加 的測試結果


  • .NET Framework : 就像大家所知的,動態字串相加表現最好的為 stringBuilder,在執行時間與使用記憶體用量數據都是優於其他方法;string.Format 則是最後一名
  • .NET Core : 與 .NET Framework 相同表現最好的為 stringBuilder,相同代碼在 .NET Core 執行速度提升一倍 (除了 string.Format ),速度上最慢的依舊為 string.Format,恭喜 string.Format 在各項測試蟬聯墊底

  • 感想
    多年前曾經拜讀過黑暗大文章 StringBuilder串接字串的迷思,因此進行測試前心理大致有個答案,從以上測試結果來看,stringBuilder 在動態字串相加時效能比 string 好同樣可套用到 .NET Core 上面,另外 string.Format 不管是在動態或是靜態字串相加效能都是墊底,但在可讀性上是比較好的 (大家比較習慣?),日後在 Code Review 時並依據當下情境做適合的應用,Happy Coding :)

    Related Posts:

    • [NETCore] String 字串相加效能比較 前言 在 .NET 應用程式中很常使用到 string 型別,string 是不可變 ( Immutable ) 的,當每次建立完就會固定其長度,如果要做相加就必須捨棄原有使用的記憶體,在重新配置一塊新的記憶體給它使用,如果在需要大量得字串動態相加時就會影響到其效能,因此在動態文字相加情境就可以透過 stringBuilder 來改善此問題,詳細細節可以參考黑暗大的 StringBuilder串接字串的迷思,這篇重點是在 C# 有提供多… Read More
    • [Benchmark] String 比較字串效能分析前言 在 .NET 開發時很常會用到字串的比對,C# 中提供多種字串比對的方式,這篇文章就列出在 C# 提供的字串比方法,針對這幾種常用的方法使用  BenchmarkDotNet  做效能的測試及比對,並會在 .NET Framework 與 .NET Core 分別測試結果,若有問題或是錯誤的地方歡迎各位給予指導及討論。 測試代碼  測試使用  BenchmarkDotNe… Read More
    • [NETCore] 動態 String 字串相加效能比較 前言 在前一篇 [.NETCore] String 字串相加效能比較 對於 C# string 的應用做了一些測試,得到在使用固定字串相加時使用 string 效能反而比 stringBuilder 來的好,在 string  有多種應用情境因此這篇就在針對另一種使用情境針對 string 動態文字相加做比較若有問題或是錯誤的地方歡迎各位給予指導及討論。 測試代碼  測試方式同樣以  B… Read More
    • [NETCore] 使用 BenchmarkDotNet 測試程式碼效能前言 在開發或是 POC 時為了記錄代碼程式執行的時間,都會採用在代碼上加上  stopWatch  紀錄花費時間,使用方式不外乎就是 new Stopwatch、Start、Stop、Reset、ElapsedMilliseconds,以詳細記錄代碼所花費的時間,接下來為了要顯示在 console 上可能還要針對 log 在輸出內容做簡單排版方便記錄,最近發現上述惱人的事情都可以使用  Benc… Read More

    0 意見:

    張貼留言

    Copyright © 2025 m@rcus 學習筆記 | Powered by Blogger

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com