我理解String和StringBuilder之间的区别(StringBuilder是可变的),但两者之间有很大的性能差异吗?

我正在工作的程序有很多case驱动的字符串追加(500+)。使用StringBuilder是更好的选择吗?


当前回答

StringBuilder更适合从许多非常量值构建字符串。

If you're building up a string from a lot of constant values, such as multiple lines of values in an HTML or XML document or other chunks of text, you can get away with just appending to the same string, because almost all compilers do "constant folding", a process of reducing the parse tree when you have a bunch of constant manipulation (it's also used when you write something like int minutesPerYear = 24 * 365 * 60). And for simple cases with non-constant values appended to each other, the .NET compiler will reduce your code to something similar to what StringBuilder does.

但是当你的append不能被编译器简化为更简单的东西时,你将需要一个StringBuilder。正如fizch所指出的,这更有可能发生在循环内部。

其他回答

StringBuilder是可取的,如果你正在做多个循环,或分叉在你的代码传递…然而,对于PURE性能,如果你可以使用SINGLE字符串声明,那么性能就会更好。

例如:

string myString = "Some stuff" + var1 + " more stuff"
                  + var2 + " other stuff" .... etc... etc...;

更有表现力吗

StringBuilder sb = new StringBuilder();
sb.Append("Some Stuff");
sb.Append(var1);
sb.Append(" more stuff");
sb.Append(var2);
sb.Append("other stuff");
// etc.. etc.. etc..

在这种情况下,可以认为StringBuild更易于维护,但性能并不比单个字符串声明更好。

但是十有八九……使用字符串构建器。

另一方面:string + var也比string的性能更好。格式方法(通常)在内部使用StringBuilder(如果有疑问…检查反射器!)

StringBuilder明显更高效,但除非您进行大量的字符串修改,否则无法看到这种性能。

下面是给出性能示例的一小段代码。正如您所看到的,只有当您进入大型迭代时,您才真正开始看到主要的性能提升。

正如您所看到的,20万次迭代花费了22秒,而使用StringBuilder的100万次迭代几乎是瞬间完成的。

string s = string.Empty;
StringBuilder sb = new StringBuilder();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 50000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 200000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();
Console.WriteLine("Beginning Sb append at " + DateTime.Now.ToString());

for (int i = 0; i <= 1000000; i++)
{
    sb.Append("A");
}
Console.WriteLine("Finished Sb append at " + DateTime.Now.ToString());

Console.ReadLine();

以上代码的结果:

开头字符串+在28/01/2013 16:55:40。 完成字符串+在28/01/2013 16:55:40。 开头字符串+在28/01/2013 16:55:40。 完成字符串+在28/01/2013 16:56:02。 开始Sb追加在28/01/2013 16:56:02。 完成Sb的追加在28/01/2013 16:56:02。

使用字符串进行连接会导致运行时复杂度达到O(n^2)的量级。

如果使用StringBuilder,需要复制的内存就会少得多。使用StringBuilder(int capacity),如果您可以估计最终字符串的大小,则可以提高性能。即使不精确,也可能只需要将StringBuilder的容量增加几倍,这也有助于提高性能。

StringBuilder更适合从许多非常量值构建字符串。

If you're building up a string from a lot of constant values, such as multiple lines of values in an HTML or XML document or other chunks of text, you can get away with just appending to the same string, because almost all compilers do "constant folding", a process of reducing the parse tree when you have a bunch of constant manipulation (it's also used when you write something like int minutesPerYear = 24 * 365 * 60). And for simple cases with non-constant values appended to each other, the .NET compiler will reduce your code to something similar to what StringBuilder does.

但是当你的append不能被编译器简化为更简单的东西时,你将需要一个StringBuilder。正如fizch所指出的,这更有可能发生在循环内部。

这个基准测试表明,当组合3个或更少字符串时,常规连接更快。

http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/

StringBuilder可以在内存使用方面做出非常显著的改进,特别是在将500个字符串加在一起的情况下。

考虑下面的例子:

string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
    buffer += i.ToString();
}
return buffer;

内存中发生了什么?创建以下字符串:

1 - "The numbers are: "
2 - "0"
3 - "The numbers are: 0"
4 - "1"
5 - "The numbers are: 01"
6 - "2"
7 - "The numbers are: 012"
8 - "3"
9 - "The numbers are: 0123"
10 - "4"
11 - "The numbers are: 01234"
12 - "5"
13 - "The numbers are: 012345"

通过将这5个数字加到字符串的末尾,我们创建了13个字符串对象!其中12个是无用的!哇!

StringBuilder fixes this problem. It is not a "mutable string" as we often hear (all strings in .NET are immutable). It works by keeping an internal buffer, an array of char. Calling Append() or AppendLine() adds the string to the empty space at the end of the char array; if the array is too small, it creates a new, larger array, and copies the buffer there. So in the example above, StringBuilder might only need a single array to contain all 5 additions to the string-- depending on the size of its buffer. You can tell StringBuilder how big its buffer should be in the constructor.