[Performance][C#]StringBuilder與String.Join串接字串時的效能比較

這陣子在寫程式寫到要用分隔符號串接字串的時候,想到兩種方法:一種是透過StringBuilder去串字串、一種是先把字串塞到字串陣列,再用String.Join去串字串。雖然StringBuilder對於字串的串接效能做了很大的改善,但我直覺上仍認為後者效率比前者來得佳,特此做個實驗。

測試程式碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string result=””;
int count = 1000;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < count; i++)
{
result=Test1();
}
sw.Stop();
Console.WriteLine(“Method: String.Join”);
Console.WriteLine(“Elapsed Time: “+sw.ElapsedMilliseconds );
Console.WriteLine(“Result: “ + result);

sw = Stopwatch.StartNew();
for (int i = 0; i < count; i++)
{
result = Test2();
}
sw.Stop();
Console.WriteLine(“Method: StringBuilder”);
Console.WriteLine(“Elapsed Time: “ + sw.ElapsedMilliseconds);
Console.WriteLine(“Result: “ + result);
}

static string Test1()
{
int count = 1000;
string[] strList = new string[count];
for (int i = 0; i < count; i++)
{
strList[i] = i.ToString();
}
return string.Join(“,”, strList);
}

static string Test2()
{
StringBuilder strList = new StringBuilder();
int count = 1000;
for (int i = 0; i < count-1; i++)
{
strList.Append (i.ToString() + “,”);
}
return strList.Append((count-1).ToString()).ToString ();
}
}

}

執行結果

image

image

這樣看起來String.join方法是比較優一點,但後來經Ammon網友提醒發現這樣的試驗仍有著不公正的因素存在,故測試出來的結果是不正確的。這邊將其實驗代碼修改ㄧ下,把

strList.Append (i.ToString() + “,”); 


改為

strList.Append(i);
strList.Append(“,”);

順便加入下面程式碼讓兩個要測試的方法先行編譯,以避免JIT Compiler造成不必要的誤差。

//Let JIT compiler precompiler
Test1(1);
Test2(1);

完整程式碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication17
{
class Program
{
static void Main(string[] args)
{
int testTimes = 10;
int dataCount = 1000000;
GoTest(dataCount, testTimes);
}

static void GoTest(int dataCount,int testTimes)
{
//Let JIT compiler precompiler
Test1(1);
Test2(1);

//Test performance
Stopwatch sw;
long[] elapsedTimes = new long[testTimes];

Console.WriteLine(“String.Join…”);
for (int i = 0; i < testTimes; i++)
{
sw = Stopwatch.StartNew();
Test1(dataCount);
elapsedTimes[i] = sw.ElapsedMilliseconds;
Console.WriteLine(“Elapsed Time: “ + elapsedTimes[i]);
}
Console.WriteLine(“Average Elapsed Time: “ + elapsedTimes.Average().ToString());


Console.WriteLine();
Console.WriteLine(“StringBuilder…”);
for (int i = 0; i < testTimes; i++)
{
sw = Stopwatch.StartNew();
Test2(dataCount);
elapsedTimes[i] = sw.ElapsedMilliseconds;
Console.WriteLine(“Elapsed Time: “ + elapsedTimes[i]);
}
Console.WriteLine(“Average Elapsed Time: “ + elapsedTimes.Average().ToString());
}

static string Test1(int count)
{
string[] strList = new string[count];
for (int i = 0; i < count; i++)
{
strList[i] = i.ToString();
}
return string.Join(“,”, strList);
}

static string Test2(int count)
{
StringBuilder strList = new StringBuilder();
for (int i = 0; i < count - 1; i++)
{
strList.Append(i);
strList.Append(“,”);
}
return strList.Append(count - 1).ToString();
}
}
}

為避免誤差,這邊多運行了幾次,運行結果如下:

image

image

image