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

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


从内存的角度来看,StringBuilder的性能会更好。至于处理,执行时间的差异可以忽略不计。


我相信StringBuilder更快,如果你有超过4个字符串,你需要附加在一起。此外,它可以做一些很酷的事情,如AppendLine。


在. net中,StringBuilder仍然比追加字符串快。我很确定在Java中,它们只是在附加字符串时在底层创建了一个StringBuffer,所以没有真正的区别。我不确定为什么他们还没有在。net中这样做。


是的,性能差异是显著的。请参阅KB文章“如何在Visual c#中提高字符串连接性能”。

我总是试着先编写清晰的代码,然后再优化性能。这比反过来做要容易得多!但是,看到了两者在我的应用程序中的巨大性能差异后,我现在更仔细地考虑了一下。

幸运的是,在代码上运行性能分析相对简单,可以看到您在哪些地方花费了时间,然后在需要的地方修改它以使用StringBuilder。


StringBuilder is probably preferable. The reason is that it allocates more space than currently needed (you set the number of characters) to leave room for future appends. Then those future appends that fit in the current buffer don't require any memory allocation or garbage collection, which can be expensive. In general, I use StringBuilder for complex string concatentation or multiple formatting, then convert to a normal String when the data is complete, and I want an immutable object again.


如果你要做很多字符串连接,使用StringBuilder。当您连接一个String时,每次都会创建一个新的String,这会占用更多的内存。

Alex


除了前面的答案,当我想到这样的问题时,我总是做的第一件事是创建一个小型测试应用程序。在这个应用程序中,为这两种情况执行一些计时测试,看看哪个更快。

恕我直言,添加500+字符串条目绝对应该使用StringBuilder。


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

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


StringBuilder减少了分配和赋值的数量,代价是使用了额外的内存。如果使用得当,它可以完全消除编译器需要一遍又一遍地分配越来越大的字符串,直到找到结果为止。

string result = "";
for(int i = 0; i != N; ++i)
{
   result = result + i.ToString();   // allocates a new string, then assigns it to result, which gets repeated N times
}

vs.

String result;
StringBuilder sb = new StringBuilder(10000);   // create a buffer of 10k
for(int i = 0; i != N; ++i)
{
   sb.Append(i.ToString());          // fill the buffer, resizing if it overflows the buffer
}

result = sb.ToString();   // assigns once

我的方法一直是在连接4个或更多字符串时使用StringBuilder 或 当我不知道有多少串联会发生。

好的性能相关文章在这里


String和StringBuilder实际上都是不可变的,StringBuilder内置了缓冲区,允许更有效地管理其大小。当StringBuilder需要调整大小时,就是在堆上重新分配它的时候。默认情况下,它的大小为16个字符,您可以在构造函数中设置此值。

eg.

StringBuilder sb = new StringBuilder(50);


为了澄清Gillian所说的4弦,如果你有这样的东西:

string a,b,c,d;
 a = b + c + d;

那么使用字符串和加号运算符会更快。这是因为(就像Eric指出的Java一样),它在内部自动使用StringBuilder(实际上,它使用StringBuilder也使用的原语)

但是,如果你正在做的事情接近:

string a,b,c,d;
 a = a + b;
 a = a + c;
 a = a + d;

然后你需要显式地使用一个StringBuilder。. net在这里不会自动创建一个StringBuilder,因为这毫无意义。在每行的末尾,"a"必须是一个(不可变的)字符串,因此它必须在每行上创建和释放一个StringBuilder。为了提高速度,你需要使用相同的StringBuilder,直到你完成构建:

string a,b,c,d;
StringBuilder e = new StringBuilder();
 e.Append(b);
 e.Append(c);
 e.Append(d);
 a = e.ToString();

这个基准测试表明,当组合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.


我已经看到,在StringBuilder的实例上使用EnsureCapacity(int capacity)方法调用,然后再将它用于任何字符串存储,可以显著提高性能。我通常在实例化后的代码行中调用它。它的效果和你这样实例化StringBuilder是一样的:

var sb = new StringBuilder(int capacity);

该调用会提前分配所需的内存,从而在多个Append()操作期间减少内存分配。您必须对需要多少内存做出有根据的猜测,但对于大多数应用程序来说,这应该不会太难。我通常会在内存过多的情况下犯错(我们说的是1k左右)。


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(如果有疑问…检查反射器!)


字符串连接将花费更多。 在Java中,您可以根据需要使用StringBuffer或StringBuilder。 如果您想要一个同步的、线程安全的实现,请使用StringBuffer。这将比字符串连接更快。

如果你不需要同步的或者线程安全的实现,选择StringBuilder。 这将比String连接更快,也比StringBuffer更快,因为它们没有同步开销。


作为一般的经验法则,如果我必须设置字符串的值不止一次,或者如果字符串有任何追加,那么它需要是一个字符串构建器。在了解字符串构建器之前,我曾经看到我过去编写的应用程序具有巨大的内存足迹,而且似乎一直在不断增长。将这些程序更改为使用字符串构建器可以显著减少内存使用。现在我对琴弦制造者发誓。


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所指出的,这更有可能发生在循环内部。


以“微优化剧场的悲剧”为例。


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.

来源:MSDN


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。


一个简单的例子来演示使用String连接和StringBuilder在速度上的差异:

System.Diagnostics.Stopwatch time = new Stopwatch();
string test = string.Empty;
time.Start();
for (int i = 0; i < 100000; i++)
{
    test += i;
}
time.Stop();
System.Console.WriteLine("Using String concatenation: " + time.ElapsedMilliseconds + " milliseconds");

结果:

使用字符串串联:15423毫秒

StringBuilder test1 = new StringBuilder();
time.Reset();
time.Start();
for (int i = 0; i < 100000; i++)
{
    test1.Append(i);
}
time.Stop();
System.Console.WriteLine("Using StringBuilder: " + time.ElapsedMilliseconds + " milliseconds");

结果:

使用StringBuilder: 10毫秒

结果,第一次迭代花费了15423毫秒,而使用StringBuilder的第二次迭代花费了10毫秒。

在我看来,使用StringBuilder更快,快得多。


是的,StringBuilder在对字符串执行重复操作时提供了更好的性能。这是因为所有的更改都是对单个实例进行的,因此它可以节省大量时间,而不是像String那样创建一个新实例。

String Vs Stringbuilder

字符串 系统命名空间下 不可变(只读)实例 当价值发生持续变化时,性能下降 线程安全的 StringBuilder(可变字符串) 在系统。文本名称空间 可变的实例 显示更好的性能,因为对现有实例进行了新的更改

强烈推荐dotnet mob文章:c#中的String Vs StringBuilder。 相关堆栈溢出问题:字符串时的可变性 在c#中没有改变?


字符串Vs字符串生成器:

你要知道的第一件事是这两个类生活在哪个汇编中?

So,

字符串出现在系统命名空间中。

and

StringBuilder出现在系统中。文本名称空间。

对于字符串声明:

您必须包括System名称空间。 就像这样。 使用系统;

and

对于StringBuilder声明:

你必须包括系统。文本名称空间。 就像这样。 使用text;

现在真正的问题来了。

string和StringBuilder之间的区别是什么?

两者的主要区别在于:

字符串是不可变的。

and

StringBuilder是可变的。

现在让我们讨论一下immutable和mutable的区别

Mutable::意思是可变的。

Immutable::表示不可更改。

例如:

using System;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // String Example

            string name = "Rehan";
            name = name + "Shah";
            name = name + "RS";
            name = name + "---";
            name = name + "I love to write programs.";

            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah RS --- I love to write programs."
        }
    }
}

在这种情况下,我们要将同一个对象改变5次。

所以显而易见的问题是!当我们修改同一个字符串5次时,实际上发生了什么。

这就是当我们改变同一个字符串5次时发生的情况。

让我们看一下图表。

解释:

当我们第一次将变量name初始化为Rehan时i-e string name = "Rehan" 这个变量被创建在堆栈“name”上,并指向“Rehan”值。 "name = name + "Shah"。引用变量不再指向对象“Rehan”,而是指向“Shah”,以此类推。

string是不可变的意思是一旦我们在内存中创建了对象我们就不能改变它们。

因此,当我们连接name变量时,前一个对象仍然在内存中,另一个新的字符串对象被创建。

所以从上图中我们有五件物品,四件物品被扔掉了,它们根本不用。它们仍然保留在内存中,并占据一定的内存容量。 “垃圾回收器”负责清理内存中的资源。

在字符串的情况下,当我们反复操作字符串时我们有很多对象被创建并留在内存中。

这就是字符串变量的故事。

现在让我们看看StringBuilder对象。 例如:

using System;
using System.Text;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // StringBuilder Example

            StringBuilder name = new StringBuilder();
            name.Append("Rehan");
            name.Append("Shah");
            name.Append("RS");
            name.Append("---");
            name.Append("I love to write programs.");


            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah Rs --- I love to write programs."
        }
    }
}

在这种情况下,我们要将同一个对象改变5次。

所以显而易见的问题是!当我们修改同一个StringBuilder 5次时,实际上发生了什么。

这就是当我们修改同一个StringBuilder 5次时所发生的情况。

让我们看一下图表。

解释: 对于StringBuilder对象。你不会得到新对象。同一个对象会在内存中发生变化,所以即使你改变对象10000次,我们仍然只有一个stringBuilder对象。

你没有很多垃圾对象或非_referenced stringBuilder对象,因为它可以被更改。它是可变的意思是它会随着时间变化?

差异:

字符串存在于系统命名空间中,其中Stringbuilder存在 在系统。文本名称空间。 string是不可变的,而StringBuilder是可变的。