2009-10-23 104 views
16

我有一種情況,我需要連接幾個字符串以形成一個類的id。基本上我只是在列表中循環獲取對象的ToString值,然後將它們連接起來。字符串連接vs字符串生成器。性能

foreach (MyObject o in myList) 
    result += o.ToString(); 

名單預計不會有超過5個元素(雖然它可以,但是這是一個非常,非常邊際的情況下),通常都會有1到3個元素,是普遍的情況只是有一個或二。

什麼是更多的性能,保持串聯或使用StringBuilder?

StringBuilder bld = new StringBuilder() 
foreach (MyObject o in myList) 
    bld.Append(o.ToString()); 

我不確定創建StringBuilder是否需要比標準連接更多的時間用於最常見的情況。

這是懶惰的,列表中的項目一旦創建就不會改變,所以當被調用時id是懶惰地構造的。

作爲一個方面說明...我應該使用固定的數組而不是List嗎?如果我這樣做,我會得到任何表現或記憶改善嗎? (無論如何,列表只能用作IEnumerable)

問題的更一般的觀點可能是,有多少個字符串足以停止連接並開始構建?

我是否應該甚至費心去測試這種情況?

if (myList.Count > 4) 
    ConcatWithStringBuilder(myList); 
+0

這將是一個完美的情況下進行微觀優化。甚至不要打擾這個數量的琴絃。 – 2009-10-23 11:28:03

+1

可能的微秒差距是否值得您的麻煩?編寫這個問題花費的時間可能比在程序生命週期中concat/builder的區別要多。特別是如果它很懶,並且每次執行只調用一次。 – 2009-10-23 12:09:50

+0

[String StringBuilder]的可能的重複(https://stackoverflow.com/questions/73883/string-vs-stringbuilder) – Matt 2017-07-14 08:12:05

回答

23

通常的答案是字符串連接對於4到8個字符串更有效。這取決於您閱讀的是誰的博客。

不要編寫測試來決定使用哪種方法。如果你不確定它是否會超過魔術極限,那麼就使用StringBuilder。

運行這段代碼看看效果如何:

const int sLen=30, Loops=5000; 
DateTime sTime, eTime; 
int i; 
string sSource = new String('X', sLen); 
string sDest = ""; 
// 
// Time string concatenation. 
// 
sTime = DateTime.Now; 
for(i=0;i<Loops;i++) sDest += sSource; 
eTime = DateTime.Now; 
Console.WriteLine("Concatenation took " + (eTime - sTime).TotalSeconds + " seconds."); 
// 
// Time StringBuilder. 
// 
sTime = DateTime.Now; 
System.Text.StringBuilder sb = new System.Text.StringBuilder((int)(sLen * Loops * 1.1)); 
for(i=0;i<Loops;i++) sb.Append(sSource); 
sDest = sb.ToString(); 
eTime = DateTime.Now; 
Console.WriteLine("String Builder took " + (eTime - sTime).TotalSeconds + " seconds."); 
// 
// Make the console window stay open 
// so that you can see the results when running from the IDE. 
// 
Console.WriteLine(); 
Console.Write("Press Enter to finish ... "); 
Console.Read(); 

參考。 http://support.microsoft.com/kb/306822

+1

我認爲在這個問題上存在困惑,這取決於你尊重你的意見。根據我的理解,底線是隻有當代碼經常受到重大負載時纔會出現性能差異。 – 2009-10-23 12:47:35

+0

@Aliixx:我完全同意。 – 2009-10-23 13:44:50

+0

@Foxfire:好吧,讓我們說一篇文章,介紹幾種不同的視圖,說明在字符串和StringBuilder之間進行選擇的拼接數量是多少「 – 2009-10-23 13:46:46

0

在這種情況下,字符串生成器很可能會稍微快一些,但實際上它可能不足以讓您煩惱。它真的要取決於兩件事情,即重新創建字符串的次數(因爲字符串是不可變的,並且連接強制從兩個現有字符串創建新字符串)以及字符串元素的大小串聯在一起。連接5個字符串,每個字節2個字節將與將5個字符串連接在一起(每個字節5000個字節)非常不同,因爲字符串越長,系統爲分配內存和垃圾收集對象所做的工作就越多使用時間更長。字符串生成器是一個更好的選擇,因爲它已經被優化,可以將字符串連接在一起,並且您不必擔心性能方面的考慮。

考慮到所有這些,如果您知道最終字符串的最終大小有多大,字符串生成器幾乎肯定會更快。當你告訴它爲最終字符串分配多少內存時,它不必經過重新分配內存的過程。

0

如果您可以估計將用於完整字符串的字節數(並使用它來初始化StringBuilder的容量),那麼當執行超過大約3個連接時,StringBuilder可能會優於String類。

11

我支持保持簡單的想法,直到你有充分的理由使它們變得複雜。

對於類似2-5元素的東西,使用StringBuilder沒有意義(除非您不斷重複此連接)。更好的可讀語法「+ =」具有更多的價值。

+0

我應該甚至打擾測試案例嗎? – 2009-10-23 11:26:17

+2

如果你好奇,爲什麼不呢? – 2009-10-23 11:27:07

+0

不,我的意思是測試如果列表中的對象數量大於X do StringBuilder,oc do concat。我更新了這個問題的主體:) – 2009-10-23 11:28:31

0

我會使用StringBuilder只是因爲你想在整個應用程序中保持一致。實例化一個Java/.NET對象也不費時,但我猜想在爲StringBuilder設置時會有一些內務管理。沒有太多比通過串聯創建多個String對象更糟糕。

3

這個問題的更一般的觀點可能是,有多少個字符串足以停止連接並開始構建?

這依賴於字符串的長度,如果你能預測目標長度,那麼你應該提供的長度爲StringBuilder構造,如果你將它們連接起來一次全部或幾個步驟中。

如果將它們連接起來,在一次(如s = "A" + "b" + "c" + "d"然後使用StringBuilder可能永遠是有道理的。

如果您可以準確預測長度,那麼即使是3個字符串StringBuilder也會更快。

如果您的連接數超過5個,通常StringBuilder會更快。但即使如此,串聯字符串通常也沒有多少開銷(除非它運行在一個緊密的循環中)。

一旦使用StringBuilder達到10個連接,可能會有利。

編輯:只是要說清楚:在你的情況下,你應該明確去沒有StringBuilder

1

IMO字符串連接更具可讀性。您可以使用+和+ =來代替strBldInstance.Add(),它可以讓代碼更加渾濁,StringBuilder的存在使得連接更加高效,但是我通常會犧牲代碼可讀性的性能。你的代碼不會受到影響,如果你在這裏和那裏都會碰到一些字符串。對於經常使用很多字符串的代碼塊,請使用StringBuilder。

0

如果可以的話,你可以有一些樂趣,完全消除for循環並使用聚合?

var concatstring = mylist.Aggregate("", (acc, item) => acc + "." + item); 

不知道在這個雖然開銷?

+1

儘管這是從7年前開始的...... Linq總是比直接循環慢,因爲它是一個內部循環,帶有很多額外的函數調用。我傾向於認爲性能優化總是會導致把Linq扔掉,而不是把它帶入.Linq是關於可讀性的;不是表演... – FrankB 2016-11-09 09:43:37