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

发布于 2024-07-13 15:08:47 字数 326 浏览 6 评论 0原文

最近,我发现自己使用 StringBuilder 来处理所有大小的字符串连接,但是在最近的性能测试中,我替换了同事的 stringOut = string1 + "." StringBuilder 的 string2 样式连接(在 10000x + 循环中使用,每次都会更新 StringBuilder),只是为了看看它在较小的连接中会产生什么差异。

我发现,在性能测试的多次运行中,无论连接还是 StringBuilder,变化都没有显着的升高或降低(重申这是针对连接)。

在什么情况下,“更新” StringBuilder 对象会抵消使用该对象的好处?

Recently I have found myself using StringBuilder for all string concatenations, big and small, however in a recent performance test I swapped out a colleague's stringOut = string1 + "." string2 style concatenation (being used in a 10000x + loop with the StringBuilder being newed each time) for a StringBuilder just to see what difference it would make in a minor concatenation.

I found, over many runs of the performance test, the change was both insignificantly higher or lower regardless of concatenation or StringBuilder (restating this was for small concatenations).

At what point does the 'newing up' of a StringBuilder object negate the benefits of using one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

荒芜了季节 2024-07-20 15:08:47

我遵循的规则是 -

当编译时串联数量未知时使用 StringBuilder。

因此,在您的情况下,每个 StringBuilder 仅附加几次,然后被丢弃。 之类的东西并不相同,因为否则您将不断分配新内存。

string s = String.Empty;
for (int i = 0; i < 10000; ++i)
{
    s += "A";
}

这与使用 StringBuilder 会极大提高性能

The rule that I follow is -

Use a StringBuilder when the number of concatenations is unknown at compile time.

So, in your case each StringBuilder was only appending a few times and then being discarded. That isn't really the same as something like

string s = String.Empty;
for (int i = 0; i < 10000; ++i)
{
    s += "A";
}

Where using a StringBuilder would drastically improve performance because you would otherwise be constantly allocating new memory.

宣告ˉ结束 2024-07-20 15:08:47

我确信我已经得到了另一个答案,我只是发布了指向我的文章的链接 然后是总结,但我们又来了。

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

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

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

  • 如果您需要连接的中间结果而不是提供下一次连接迭代,则 StringBuilder 不会为您提供帮助。 例如,如果您从名字和姓氏构建全名,然后在末尾添加第三条信息(可能是昵称),那么您只会从使用 StringBuilder 中受益code> 如果您不需要(名字 + 姓氏)字符串用于其他目的(就像我们在创建 Person 对象的示例中所做的那样)。

  • 如果您只需要做一些串联,并且您确实想在单独的语句中执行它们,那么采用哪种方式并不重要。 哪种方式更有效取决于连接的数量、所涉及的字符串的大小以及连接的顺序。如果您确实认为该代码段是性能瓶颈,请对它进行分析或基准测试。

I'm sure I've got another answer where I posted just a link to my article and then its summary, but here we go again.

  • Definitely use StringBuilder when you're concatenating in a non-trivial loop - especially if you don't know for sure (at compile time) how many iterations you'll make through the loop. For example, reading a file a character at a time, building up a string as you go using the += operator is potentially performance suicide.

  • Definitely use the concatenation operator when you can (readably) specify everything which needs to be concatenated in one statement. (If you have an array of things to concatenate, consider calling String.Concat explicitly - or String.Join if you need a delimiter.)

  • Don't be afraid to break literals up into several concatenated bits - the result will be the same. You can aid readability by breaking a long literal into several lines, for instance, with no harm to performance.

  • If you need the intermediate results of the concatenation for something other than feeding the next iteration of concatenation, StringBuilder isn't going to help you. For instance, if you build up a full name from a first name and a last name, and then add a third piece of information (the nickname, maybe) to the end, you'll only benefit from using StringBuilder if you don't need the (first name + last name) string for other purpose (as we do in the example which creates a Person object).

  • If you just have a few concatenations to do, and you really want to do them in separate statements, it doesn't really matter which way you go. Which way is more efficient will depend on the number of concatenations the sizes of string involved, and what order they're concatenated in. If you really believe that piece of code to be a performance bottleneck, profile or benchmark it both ways.

西瓜 2024-07-20 15:08:47

有时值得查看文档

串联的性能
字符串或的操作
StringBuilder 对象取决于如何
经常会发生内存分配。 A
字符串连接操作始终
分配内存,而a
StringBuilder串联操作
仅在以下情况下分配内存
StringBuilder对象缓冲区太
小以容纳新数据。
因此,String 类是
更适合串联
如果固定数量的 String 则进行操作
对象是串联的。 在那里面
情况下,单独串联
操作甚至可以合并为
编译器的单个操作。 A
StringBuilder 对象更适合
串联操作,如果
任意数量的字符串是
连接; 例如,如果一个循环
连接随机数
用户输入的字符串。

在您的示例中,每个输出字符串只有一个串联,因此 StringBuilder 不会给您带来任何好处。 如果您多次添加同一个字符串,则应该使用 StringBuilder,例如:

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

Sometimes it's worth looking at the documentation:

The performance of a concatenation
operation for a String or
StringBuilder object depends on how
often a memory allocation occurs. A
String concatenation operation always
allocates memory, whereas a
StringBuilder concatenation operation
only allocates memory if the
StringBuilder object buffer is too
small to accommodate the new data.
Consequently, the String class is
preferable for a concatenation
operation if a fixed number of String
objects are concatenated. In that
case, the individual concatenation
operations might even be combined into
a single operation by the compiler. A
StringBuilder object is preferable for
a concatenation operation if an
arbitrary number of strings are
concatenated; for example, if a loop
concatenates a random number of
strings of user input.

In your example, there is only a single concatenation per output string, so StringBuilder gains you nothing. You should use StringBuilder in cases where you are adding to the same string many times, e.g.:

stringOut = ...
for(...)
    stringOut += "."
    stringOut += string2
不再让梦枯萎 2024-07-20 15:08:47

我的经验法则很简单。

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

根据我的经验,诸如: 的表达式

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

比: 更容易编写和理解

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

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

另一方面,当需要随着时间(随着程序运行)或空间(由来自代码不同部分的值组成)累积字符串时,以某种方式编写为单行表达式是不切实际的,那么 StringBuilder 可以避免以下开销(时间和内存搅动):

String s = somethingExpression;
...
s += someOtherExpression;
...
s += yetAnotherExpression;
...

My rule of thumb is simple.

  1. If you reasonably can write a single expression that produces the final, then use +.
  2. If you can't (due either to size or variability), then use StringBuilder.

In my experience, expressions such as:

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

can be written and understood much more easily than:

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

(followed by using the string from sb where the above expression would have been written), and it performs equally well (hint: look at the compiled code to see why!)

On the other hand, when there's need to accumulate a string over time (as the program runs) or space (made up of values coming from different parts of the code), in a way that is impractical to write as a single-line expression, then StringBuilder avoids the overhead (time and memory-churning) of:

String s = somethingExpression;
...
s += someOtherExpression;
...
s += yetAnotherExpression;
...
等你爱我 2024-07-20 15:08:47

来自 MSDN

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

我想答案是“这取决于” - 如果您在一个循环内连接多次迭代,那么 StringBuilder 几乎总是会提供更好的性能,但唯一确定的方法是实际分析。

From MSDN:

[T]he String class is preferable for a
concatenation operation if a fixed
number of String objects are
concatenated. In that case, the
individual concatenation operations
might even be combined into a single
operation by the compiler. A
StringBuilder object is preferable for
a concatenation operation if an
arbitrary number of strings are
concatenated; for example, if a loop
concatenates a random number of
strings of user input.

I guess the answer is "it depends" - if you're concatenating inside a loop with more than a handful of iterations then a StringBuilder will almost always deliver better performance, but the only way to know for sure is to actually profile.

甜扑 2024-07-20 15:08:47

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

There's an interesting article on this over at Coding Horror. Jeff got the following results for 100,000 iterations on a dual core 3.5 GHz Core 2 Duo:

 Simple Concatenation    - 606 ms
 String.Format           - 665 ms
 string.Concat           - 587 ms
 String.Replace          - 979 ms
 StringBuilder           - 588 ms
冷情 2024-07-20 15:08:47

来自 Dot Net Perls

何时使用 StringBuilder?

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

有时,可以使用 4 次或更少迭代的小循环以及简单的字符串连接。 然而,在极端情况下,这可能是灾难性的。 使用 StringBuilder 规划您的边缘情况。

From Dot Net Perls:

When to use StringBuilder?

StringBuilder is entirely an optimization, and it offers no logical improvements to string Concat other than its internal implementation. That said, it is critical to use it correctly in your high-performance applications and web sites.

Sometimes, it is okay to use small loops of 4 or fewer iterations with simple string Concats. However, in edge cases this can be disastrous. Plan for your edge cases with StringBuilder.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文