2012-08-13 42 views
5

我有一個StringBuilder對象,其中我加入一些字符串類似如下:C#中的StringBuilder性能?

我想知道哪一個是更好的方法在這裏,第一個是這樣的:

StringBuilder sb = new StringBuilder(); 
sb.Append("Hello" + "How" + "are" + "you"); 

,第二個是:

StringBuilder sb = new StringBuilder(); 
sb.Append("Hello").Append("How").Append("are").Append("you"); 
+3

請參閱http://stackoverflow.com/questions/9132338/how-many-string-objects-will-be-created-when-using-a-plus-sign/9132374#9132374。這已被覆蓋*致死* :-) – 2012-08-13 16:04:43

+0

你可以找到[這個分析](http://www.dotnetperls.com/stringbuilder-performance)有趣 – Steve 2012-08-13 16:08:11

+0

我的問題是 - 你爲什麼要做「你好」+ 「如何」等,當「HelloHow」會好嗎?這個問題的實際問題是什麼,因爲我的答案因技術原因而受到打擊,我認爲這不是重點...... – Charleh 2012-08-13 16:24:23

回答

6

第一個會更有效率。編譯器將其轉換爲以下單呼:

StringBuilder sb = new StringBuilder(); 
sb.Append("HelloHowareyou"); 

測量性能

知道這是更快的來衡量它的最好辦法。我會得到開門見山:這裏的結果(較小的時間意味着更快):

sb.Append("Hello" + "How" + "are" + "you")     : 11.428s 
sb.Append("Hello").Append("How").Append("are").Append("you"): 15.314s 
sb.Append(a + b + c + d)         : 21.970s 
sb.Append(a).Append(b).Append(c).Append(d)     : 15.529s 

給出的數字是執行操作100萬次在緊密循環的秒數。

結論

  • 最快的是使用字符串和+
  • 但是,如果你有變量,使用Append+快。由於對String.Concat的額外呼叫,第一個版本較慢。

如果你想測試這個自己,這是我用來獲取上述定時程序:

using System; 
using System.Text; 

public class Program 
{ 
    public static void Main() 
    { 
     DateTime start, end; 
     int numberOfIterations = 100000000; 
     start = DateTime.UtcNow; 
     for (int i = 0; i < numberOfIterations; ++i) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append("Hello" + "How" + "are" + "you"); 
     } 
     end = DateTime.UtcNow; 
     DisplayResult("sb.Append(\"Hello\" + \"How\" + \"are\" + \"you\")", start, end); 

     start = DateTime.UtcNow; 
     for (int i = 0; i < numberOfIterations; ++i) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append("Hello").Append("How").Append("are").Append("you"); 
     } 
     end = DateTime.UtcNow; 
     DisplayResult("sb.Append(\"Hello\").Append(\"How\").Append(\"are\").Append(\"you\")", start, end); 

     string a = "Hello"; 
     string b = "How"; 
     string c = "are"; 
     string d = "you"; 

     start = DateTime.UtcNow; 
     for (int i = 0; i < numberOfIterations; ++i) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append(a + b + c + d); 
     } 
     end = DateTime.UtcNow; 
     DisplayResult("sb.Append(a + b + c + d)", start, end); 

     start = DateTime.UtcNow; 
     for (int i = 0; i < numberOfIterations; ++i) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append(a).Append(b).Append(c).Append(d); 
     } 
     end = DateTime.UtcNow; 
     DisplayResult("sb.Append(a).Append(b).Append(c).Append(d)", start, end); 

     Console.ReadLine(); 
    } 

    private static void DisplayResult(string name, DateTime start, DateTime end) 
    { 
     Console.WriteLine("{0,-60}: {1,6:0.000}s", name, (end - start).TotalSeconds); 
    } 
} 
10

在當前的例子中,字符串文字:

"Hello" + "How" + "are" + "you" 

由編譯器編譯成一個常量字符串,所以它在技術上比:

sb.Append("Hello").Append("How").Append("are").Append("you"); 

不過,是你使用字符串變量:

sb.Append(s1 + s2 + s3 + s4); 

那麼後者會更快,因爲前者可能之前創建了一系列(因爲串接)字符串傳遞的最後字符串轉換爲Append方法,而後者則可以避免額外的字符串創建(但可以進行額外的方法調用和內部緩衝區大小調整)。

更新:爲了進一步清楚起見,在此確切情況下僅存在4個項目是級聯,則編譯器將發出一個呼叫到String.Concat(string, string, string, string),其通過了解長度和字符串的數目將比StringBuilder更有效。

+0

是的,你會在評估表達式s1 + s2 + s3中創建3個字符串+ s4':s1 + s2-> t1,t1 + s3-> t2,t2 + s2-> t3。 – 2012-08-13 16:54:32

+0

@NicholasCarey不,在評估's1 + s2 + s3 + s4'時,唯一創建的新字符串就是結果。該表達式被編譯爲對'String.Concat'的單個調用,該調用不分配任何中間額外的字符串。 – 2012-08-14 01:18:18

+0

在這個例子中,正如其他答案所暗示的那樣,'String.Concat'可能會更快(由於'StringBuilder'完成內部調整大小)。在單個實例中,如已知數量的這種情況,我會傾向於串聯。如果數量不確定,比如循環,我會傾向'StringBuilder' – 2012-08-14 05:30:59

0

在第一種情況下,編譯器將構造一個單獨的字符串,因此您只能調用Append一次。但是,我懷疑這會造成很大的不同。你的測量結果顯示了什麼?

-5

第二個是更好的方法。字符串是不可改變的,這意味着當您使用sb.Append(「Hello」+「How」+「Are」+「You」)時,您正在創建字符串的多個副本

"Hello" 

然後

"HelloHow" 

然後

"HelloHowAre" 

代碼的第二片是更高性能的

編輯:當然這並不考慮到但最好是按照預期使用這個類

好的,人們已經指出,因爲這些是文字編譯器負責優化這些操作 - 但我的觀點是做字符串連接是StringBuilder嘗試的東西避免

例如,循環幾次這樣的:

var someString = ""; 

foreach (var s in someListOfStrings) 
{ 
    someString += s; 
} 

是不如做:

var sb = new StringBuilder(); 

foreach(var s in someListOfStrings) 
{ 
    sb.Append(s); 
} 

sb.ToString(); 

由於這很可能是因爲更快,正如我以前說過,字符串是不可變

我以爲OP談論一般採用串聯自

sb.Append("Hello" + "How"); 

似乎完全沒有意義的,當

sb.Append("HelloHow"); 

會更合乎邏輯......?

在我看來,在OP的心目中,佔位符文本最終將成爲一個變量的shedload ...

+1

你實際上並沒有這樣做 - 編譯器將它映射到一個String.Concat調用 – 2012-08-13 16:05:42

+1

'「Hello」+「How」+「Are」 +「You」'是字符串'literals',儘管 – dtsg 2012-08-13 16:06:21

+0

@john並沒有在編譯器通過它們之後,如果代碼實際上是這樣編寫的,編譯器將它們摺疊成單個字符串文字 – 2012-08-13 16:07:54

4

字符串常量將被編譯器編譯時並置。如果你是串聯不超過四個字符串表達式,編譯器將發出以String.Concat

s + t + u + v ==> String.Concat(s, t, u, v) 

這將執行比StringBuilder更快的調用,如StringBuilder可能不得不調整其內部的緩衝區,而Concat可以計算出所有的長度提前。如果預先知道將得到的字符串的最大長度,但是,可以通過指定一個初始工作緩衝器大小

var sb = new StringBuilder(initialBufferSize); 

StringBuilder通常在循環中和其他動態場景中使用初始化StringBuilder並且執行速度比s += t在這種情況下。

+0

+1爲Concat信息。 – 2012-08-13 16:54:06