在什么时候使用StringBuilder变得无关紧要或开销?

时间:2009-02-15 10:55:35

标签: .net stringbuilder

最近我发现自己使用StringBuilder进行所有字符串连接,无论大小,但是在最近的性能测试中,我换了一个同事的 stringOut = string1 +“。” string2 样式连接(用于每次新建StringBuilder的10000x +循环),用于StringBuilder只是为了看看它在次要连接中会有什么不同。

我发现,在性能测试的许多次运行中,无论是串联还是StringBuilder,更改都无论是更高还是更低(重申这是小型连接)。

StringBuilder对象的'newing up'在什么时候否定了使用它的好处?

7 个答案:

答案 0 :(得分:20)

我遵循的规则是 -

在编译时未知连接数时使用StringBuilder。

因此,在您的情况下,每个StringBuilder只会附加几次然后被丢弃。这与

之类的东西并不相同
string s = String.Empty;
for (int i = 0; i < 10000; ++i)
{
    s += "A";
}

使用StringBuilder会大大提高性能,因为否则会不断分配新的内存。

答案 1 :(得分:18)

我确信我已经找到了另一个答案,我只发布了link to my article然后发布了摘要,但是我们再来一次。

  • 当您在一个非平凡的循环中连接时,肯定会使用StringBuilder - 特别是如果您不确定(在编译时)您将通过循环进行多少次迭代。例如,一次读取一个文件,使用+ =运算符构建一个字符串可能会导致性能自杀。

  • 当你可以(可读地)指定需要在一个语句中连接的所有内容时,绝对使用连接运算符。 (如果要连接一系列事物,请考虑明确调用String.Concat - 或者如果需要分隔符则调用String.Join。)

  • 不要害怕将文字分成几个连接位 - 结果将是相同的。例如,你可以通过将长文字分成几行来提高可读性,而不会损害性能。

  • 如果您需要连接的中间结果而不是提供下一次连接迭代,StringBuilder将无法帮助您。例如,如果您从名字和姓氏建立一个全名,然后在最后添加第三条信息(可能是昵称),那么只有使用StringBuilder才能获益您不需要(名字+姓氏)字符串用于其他目的(正如我们在创建Person对象的示例中所做的那样)。

  • 如果您只是要进行一些连接,并且您真的想在单独的语句中进行这些连接,那么您走哪条路并不重要。哪种方式更有效将取决于所涉及的字符串大小的串联数量,以及它们连接的顺序。如果您确实认为该段代码是性能瓶颈,则可以两种方式进行配置或基准测试。

答案 2 :(得分:6)

有时值得查看documentation

  

串联的表现   String或的操作   StringBuilder对象取决于方式   通常会发生内存分配。一个   字符串连接操作始终   分配内存,而a   StringBuilder连接操作   只有分配内存   StringBuilder对象缓冲区也是如此   小到容纳新数据。   因此,String类是   最好是串联   操作如果是固定数量的String   对象是连接的。在那里面   个案,个别串联   甚至可以将操作合并到一起   编译器的单个操作。一个   StringBuilder对象更适合   一个连接操作,如果一个   任意数量的字符串   级联;例如,如果一个循环   连接随机数   用户输入字符串。

在您的示例中,每个输出字符串只有一个连接,因此StringBuilder不会获得任何结果。如果要多次添加相同字符串,则应使用StringBuilder,例如:

stringOut = ...
for(...)
    stringOut += "."
    stringOut += string2

答案 3 :(得分:2)

我的经验法则很简单。

  1. 如果您合理地可以编写一个产生最终结果的表达式,那么请使用+
  2. 如果你不能(由于大小或可变性),那么使用StringBuilder。
  3. 根据我的经验,表达式如:

    "Id: " + item.id + " name: " + item.name
    

    可以比以下更容易编写和理解:

    StringBuilder sb = new StringBuilder();
    sb.append("Id: ").append(item.id);
    sb.append(" name: ").append(item.name);
    

    (然后使用来自sb的字符串,其中上面的表达式已被写入),并且它的表现同样出色(提示:查看编译后的代码以了解原因!)

    另一方面,当需要随着时间的推移(当程序运行时)或空间(由来自代码的不同部分的值组成)累积字符串时,以一种单独写入的方式是不切实际的-line表达式,然后StringBuilder避免了:

    的开销(时间和内存流失)
    String s = somethingExpression;
    ...
    s += someOtherExpression;
    ...
    s += yetAnotherExpression;
    ...
    

答案 4 :(得分:1)

来自MSDN

  

[T]他的字符串类更适合a   连接操作如果是固定的   String对象的数量是   级联。在那种情况下,   个别连接操作   甚至可以组合成一个单一的   由编译器操作。一个   StringBuilder对象更适合   一个连接操作,如果一个   任意数量的字符串   级联;例如,如果一个循环   连接随机数   用户输入字符串。

我想答案是“它取决于” - 如果你在一个循环内连接超过一些迭代,那么StringBuilder几乎总能提供更好的性能,但唯一可以确定的方法是实际剖析

答案 5 :(得分:1)

Coding Horror上有一篇有趣的文章。 Jeff在双核3.5 GHz Core 2 Duo上获得了以下100,000次迭代的结果:

 Simple Concatenation    - 606 ms
 String.Format           - 665 ms
 string.Concat           - 587 ms
 String.Replace          - 979 ms
 StringBuilder           - 588 ms

答案 6 :(得分:1)

来自Dot Net Perls

何时使用StringBuilder?

StringBuilder完全是一种优化,除了内部实现之外,它不对字符串Concat进行逻辑改进。也就是说,在高性能应用程序和网站中正确使用它至关重要。

有时,使用简单的字符串Concats可以使用4次或更少次迭代的小循环。但是,在边缘情况下,这可能是灾难性的。使用StringBuilder计划边缘情况。