2009-12-29 123 views
5

所以...我有這種情況下,我有一個Foreach循環,通過複選框列表來檢查哪些被選中。對於每個選定的複選框,我必須進行一個非常長的字符串連接,包含30個平均長度爲20個字符的不同字符串,然後將其作爲HTTP請求發送出去。 2個字符串取決於所選複選框的索引/值。字符串連接VS字符串生成器追加

根據用戶的數據,複選框列表的長度也是可變的。我會說列表的平均長度是20,但可以達到50-60。所以最糟糕的情況是執行整個字符串連接60次左右。

現在我正在通過'+'運算符通過簡單字符串連接來完成它,但是我想知道用Stringbuilder做它會更快。當然,這意味着我不得不在循環中創建一個Stringbuilder對象,或者在循環之前創建它,並在發送HTTP請求之後調用Stringbuilder.Remove。

我很感激任何人都可以分享有關此問題的任何見解。

編輯
感謝所有的答覆大家,所以從我收集的,最好的辦法,我去這樣做會是這樣的:

+0

我很抱歉,看來我不太瞭解Stringbuilder。所以調用Stringbuilder.ToString()清除Stringbuilder? – Kronon 2009-12-29 05:06:14

+0

否。將Length屬性設置爲零會清除它。 – 2009-12-29 05:09:51

+0

someStringBuilder.length = 0; – 2009-12-29 05:11:24

回答

14

使用StringBuilder。這就是它的目的。

字符串是不可變的。字符串連接創建一個新字符串,需要更多的內存,通常被認爲是慢:

string a = "John" + " " + "Saunders"; 

這將創建一個字符串「約翰」,然後創建另一個字符串「約翰·桑德斯」,最後,分配,爲「一」 。 「約翰」留給垃圾收集。

string a = "John"; 
a += " "; 
a += "Saunders"; 

這是差不多的,因爲「約翰」是一個新的字符串「約翰」,這是一個新的字符串「約翰·桑德斯」取代取代。原件留給垃圾收集。

在另一方面,StringBuilder被設計爲附加,刪除等


例子:

StringBuilder sb = new StringBuilder(); 
for (int i=0; i<n; i++) 
{ 
    sb.Length = 0; 
    sb.Append(field1[i]); 
    sb.Append(field2[i]); 
    ... 
    sb.Append(field30[i]); 
    // Do something with sb.ToString(); 
} 
+0

由於某種原因我喜歡這個答案.. – 2009-12-29 04:57:26

+0

我道歉,如果我的問題似乎輕浮,但我只是想知道如果在每個循環創建一個新的Stringbuilder對象會導致不必要的開銷。 – Kronon 2009-12-29 05:01:12

+0

你爲什麼要創建一個新的? – 2009-12-29 05:02:52

2

一般來說,我會建議使用StringBuilder

您是否測試了這個並檢查了性能? 性能是一個問題,您需要多長時間來重寫代碼

+0

我幾乎完成了這個項目,所以現在我只是在尋找各種方法來優化我的代碼以獲得更好的性能。 – Kronon 2009-12-29 05:03:06

5

這個主題已經多年來分析死亡。最終的結果是,如果您正在進行少量已知數量的連接,請使用'+',否則使用stringbuilder。從你所說的,與'+'連接應該更快。有一個gazillion(給或拿)網站分析這 - 谷歌它。

對於您所說的字符串的大小,無論如何它是微不足道的。

編輯:關於第二個想法,SB可能更快。但就像我說的,誰在乎?

+2

我不同意。如果他正在做30個「+」操作,那麼他會分配並丟棄大量的字符串,而不會附加到任何字符串。 – 2009-12-29 05:00:10

+0

你在編輯時已經進入了:)我認爲SB可能會更快,但是請記住,所有'丟棄'字符串都由GC處理,它完成了相當高效的工作,而且並不真正處理當前執行路徑。 – 2009-12-29 05:03:03

+0

它仍然是不必要的GC工作,可以很容易地避免...它不像我們正在談論2或3個字符串... – 2009-12-29 05:07:20

2

如果你問這個問題,很可能你應該使用StringBuilder的原因很多,但我會提供兩個。

  1. 當你使用字符串連接它分配一個新的緩衝區,並在另一個字符串中的數據複製到新的字符串變量。所以你將會招致許多重複的分配。最後哪個最終會碎片化內存,佔用堆空間,併爲垃圾收集器做更多工作。另一方面,StringBuilder預先分配一個緩衝區,並且在向其添加字符串時不需要保持重新分配(假設初始緩衝區足夠大)。這提高了性能,對內存的徵稅也少得多。

  2. 作爲開發者,我們應該嘗試預測未來的增長。假設你的名單隨着時間的推移而大幅增長,然後突然開始緩慢地進行。如果你現在可以毫不費力地防止這種情況,那你爲什麼不這麼做?

6

我知道這已經回答了,但我想指出的是,其實,我覺得一直使用的StringBuilder的「盲目地接受福音」的做法是錯誤的,有時,這是一個情況。

爲背景,看到這個博客條目:http://geekswithblogs.net/johnsperfblog/archive/2005/05/27/40777.aspx

這樣做的缺點是,對於這種特殊情況下,如描述的那樣,你會避免的StringBuilder和利用+操作的正是如此看到更好的性能:

foreach (CheckBox item in FriendCheckboxList) 
{ 
    if (item.Checked) 
    { 
     string request = string1 + 
      string2 + 
      string3 + 
      . 
      . 
      . 
      stringLast; 
     SendRequest(request); 
    } 
} 

原因是C#編譯器(從.NET 1.1開始)會將該語句轉換爲一個單獨的IL調用,將String作爲參數傳遞給String.Concat。博客條目做了一個很好的工作,概述了String.Concat的實現細節,但足以說明,這種情況非常有效。

+0

感謝您提出這一點。很多人認爲他們在不需要時可以保存GC呼叫。如果它與性能相關,並且它可能很重要,那麼測量它!有很少的「總是使用X」規則是正確的。 – 2010-05-10 18:29:29

+1

當有固定數量的字符串連接時,string.Concat比較好。它所需要做的就是添加字符串長度的總和,分配內存,複製每個字符串,然後就完成了。如果你期望做更多的處理,StringBuilder可能會更好。 – Todd 2015-08-15 05:43:24