只有累積,沒有奇蹟

2022年11月7日 星期一

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

前言
在 .NET 應用程式中很常使用到 string 型別,string 是不可變 ( Immutable ) 的,當每次建立完就會固定其長度,如果要做相加就必須捨棄原有使用的記憶體,在重新配置一塊新的記憶體給它使用,如果在需要大量得字串動態相加時就會影響到其效能,因此在動態文字相加情境就可以透過 stringBuilder 來改善此問題,詳細細節可以參考黑暗大的 StringBuilder串接字串的迷思,這篇重點是在 C# 有提供多種語法來做 string 相加語法,像是 string.Format、stringBuilder、Concat、Join 以及 Interpolation 多種方法,今天就要針對 C# 中提供的字串相加效能進行比較,以及測試的結果數據,若有問題或是錯誤的地方歡迎各位給予指導及討論

測試代碼 
測試方式以  BenchmarkDotNet  套件協助進行測試,BenchmarkDotNet 可以針對要測試的方法紀錄執行時間,並會將測試結果輸出報告,如果對此套件有興趣可以參考介紹的文章 [.NETCore] 使用 BenchmarkDotNet 測試程式碼效能首先先針對固定字串相加做測試,定義區域變數 firstWord 與 secondWord 希望輸出 This is a book 字眼,另外在 stringBenchmark 類別加上  ClrJob,CoreJob  希望分別在 .NET Framework 與 .NET Core 測試效能差異,加上  MemoryDiagnoser  輸出測試時觀察 GC 的結果,代碼如下 
namespace benchmarkLab
{
    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<stringBenchmark>();
            Console.ReadKey();
        }
    }

    [MemoryDiagnoser]
    [ClrJob,CoreJob]
    public class stringBenchmark
    {
        private static string firstWord = "This is a";
        private static string secondWord = "book";
        StringBuilder _sb = new StringBuilder();

        // 測試代碼
    }
}
使用 Benchmark 測試數據,需要在方法上加上 Benchmark  attribute,使用 string 的相加測試的代碼如下
[Benchmark]
public void Normal()
{
    string s = string.Empty;
    s = firstWord;
    s += secondWord;
}
使用 stringBuilder 的相加測試的代碼如下
[Benchmark]
public void StringBuilder()
{
    StringBuilder sb = new StringBuilder();
    sb.Append(firstWord);
    sb.Append(secondWord);
    string s = sb.ToString();
}
另外一種使用 stringBuilder 的方式,將其宣告為區域變數使用前先 clear,測試的代碼如下
[Benchmark]
public void StringBuilderClear()
{
    _sb.Clear();
    _sb.Append(firstWord);
    _sb.Append(secondWord);
    string s = _sb.ToString();
}
使用 string.Format,測試的代碼如下
[Benchmark]
public void Format()
{
    string s = string.Empty;
    s = string.Format("{0} {1}", firstWord, secondWord);
}
使用 C# 6.0 提供的新語法 Interpolation,測試的代碼如下
[Benchmark]
public void Interpolation()
{
    string s = string.Empty;
    s = $"{firstWord}{secondWord}";
}
使用 string.Concat,測試的代碼如下
[Benchmark]
public void Concat()
{
    string s = string.Empty;
    s = string.Concat(firstWord, secondWord);
}
使用 string.Join,測試的代碼如下
[Benchmark]
public void Join()
{
    string s = firstWord;
    s += string.Join(s, secondWord);
}
接著調整到 Release mode,按下 F5 進行測試
測試完成後,會產生測試報各路徑在  release\BenchmarkDotNet.Artifacts\results  目錄底下,如下圖所示
根據測試結果


  • .NET Framework : 表現最差的為 string.Format,表現最好的是 string 相加
  • .NET Core : 表現最差的為 string.Format,表現最好的是 Interpolation

  • 感想
    透過結果得知,在 .NET Framework 與 .NET Core 環境中在 靜態字串 相加的情況下,string 相加效能會比使用 stringBuilder 來的好 (原因可以參考黑暗大文章 StringBuilder串接字串的迷思,這裡就不在細說),Interpolation 與 conact 落後一些也是表現不錯,唯有 string.Format 在兩個皆墊底,.NET Framework 最好與最差的差距近 6 倍 ( 31.9 v.s 238.0 ),在 .NET Core 更高達 9 倍 (38.2 v.s 312.2 ),如果有需要用到時需要特別留意,避免影響到網站執行效能,下次再來分享動態文字的測試數據 (拖稿),Happy Coding :)

    參考
    在 ASP.NET Core 中使用多個環境

    0 意見:

    張貼留言

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

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com