string与StringBuilder
我理解String
和StringBuilder
( StringBuilder
是可变的)之间的区别,但是两者之间有很大的性能差异吗?
我正在处理的程序有很多情况驱动的string附加(500+)。 使用StringBuilder
是一个更好的select?
是的,性能差异是显着的。 请参阅知识库文章“ 如何提高Visual C#中的string连接性能 ”。
我一直试图首先编写清晰的代码,然后再优化性能。 这比做其他事情要容易得多! 但是,我看到两者在应用上的巨大性能差异,我现在仔细想一想。
幸运的是,对代码运行性能分析比较简单,看看你在哪里花费时间,然后修改它以在需要的地方使用StringBuilder
。
为了澄清阿娇说的4弦,如果你有这样的话:
string a,b,c,d; a = b + c + d;
那么使用string和加号运算符会更快。 这是因为(就像Eric指出的那样),它自动内部使用StringBuilder(实际上,它使用了StringBuilder也使用的一个原语)
但是,如果你正在做的更接近:
string a,b,c,d; a = a + b; a = a + c; a = a + d;
那么你需要明确地使用一个StringBuilder。 .Net在这里不会自动创build一个StringBuilder,因为这没有意义。 在每一行的结尾,“a”必须是一个(不可变的)string,所以它必须在每一行上创build和configuration一个StringBuilder。 为了提高速度,在完成构build之前,您需要使用相同的StringBuilder:
string a,b,c,d; StringBuilder e = new StringBuilder(); e.Append(b); e.Append(c); e.Append(d); a = e.ToString();
StringBuilder是可取的, 如果你正在做多个循环,或在你的代码通过分叉…但是,对于PURE性能,如果你可以脱离一个单一的string声明,那么这是更高性能。
例如:
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声明更高效。
10倍的9倍,但…使用string生成器。
在一个侧面说明:string+ VAR也更高性能的String.Format方法(通常),使用StringBuilder内部(当有疑问时…检查reflection!)
该基准testing表明,组合3个或更less的string时,正则级联速度更快。
http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/
StringBuilder可以使内存使用情况得到非常显着的改善,特别是在你添加500个string的情况下。
考虑下面的例子:
string buffer = "The numbers are: "; for( int i = 0; i < 5; i++) { buffer += i.ToString(); } return buffer;
内存中发生了什么? 以下string被创build:
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"
通过将这五个数字添加到string的末尾,我们创build了13个string对象! 其中12个是无用的! 哇!
StringBuilder修复了这个问题。 它不是我们经常听到的“可变string”( 所有.NET中的string都是不可变的 )。 它通过保持一个内部缓冲区,一个字符数组。 调用Append()或AppendLine()将string添加到char数组末尾的空白处; 如果数组太小,它会创build一个新的,更大的数组,并在那里复制缓冲区。 所以在上面的例子中,StringBuilder可能只需要一个数组来包含所有5个string,这取决于它的缓冲区的大小。 你可以告诉StringBuilder缓冲区应该在构造函数中有多大。
不要盲目的去寻找StringBuilder。 有一些情况下,StringBuilder不会提高性能。
Rico Mariani写了两篇有见地的博客文章:
使用String
contactenation与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 contactenation: " + time.ElapsedMilliseconds + " milliseconds");
结果:
使用stringcontactenation: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减less了分配和分配的数量,但是使用了额外的内存。 正确使用,它可以完全消除编译器反复分配更大和更大的string直到find结果的需要。
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 }
与
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
是的, StringBuilder
在对string进行重复操作时性能更好。 这是因为所有更改都是针对单个实例进行的,因此可以节省大量时间,而不是创build像String
这样的新实例。
string与Stringbuilder
-
String
- 在
System
命名空间下 - 不可变(只读)实例
- 性能会随着价值的不断变化而降低
- 线程安全
- 在
-
StringBuilder
(可变string)- 在
System.Text
命名空间下 - 可变实例
- 由于对现有实例进行了新的更改,所以性能更好
- 在
强烈推荐dotnet mob文章: string与C#中的StringBuilder 。
相关的堆栈溢出问题: 当string在C#中没有改变时string的可变性? 。
String或StringBuilder对象的连接操作的性能取决于内存分配的频率。 如果StringBuilder对象缓冲区太小而不能容纳新数据,则String连接操作始终分配内存,而StringBuilder连接操作仅分配内存。 因此,如果串联固定数量的String对象,那么String类对于连接操作来说是可取的。 在这种情况下,编译器甚至可以将各个级联操作组合成单个操作。 如果连接任意数量的string,StringBuilder对象可以用于连接操作; 例如,如果一个循环连接了随机数的用户inputstring。
来源: MSDN
我相信StringBuilder速度更快,如果你有超过4个string你需要追加在一起。 另外它可以做一些很酷的事情,如AppendLine。
在.NET中,StringBuilder仍然比追加string快。 我很确定,在Java中,当你添加string时,他们只是创build了一个StringBuffer,所以没有什么区别。 我不知道为什么他们还没有在.NET中做到这一点。
考虑“ 微观优化剧院的悲剧悲剧 ”。
StringBuilder
更适合从许多非常量值构buildstring。
如果你从许多常量值(如HTML或XML文档中的多行值或其他文本块)中构build一个string,那么只需附加到相同的string即可,因为几乎所有的编译器都可以“常量折叠”是一个当你有一堆不断的操作(当你写int minutesPerYear = 24 * 365 * 60
时也使用它)时减lessparsing树的过程。 对于非常量值相互连接的简单情况,.NET编译器会将您的代码减less到类似于StringBuilder
所做的事情。
但是当你的append不能被编译器简化时,你需要一个StringBuilder
。 正如fizch所指出的,这更可能发生在循环内部。
使用string进行连接可能会导致运行时复杂度为O(n^2)
。
如果你使用一个StringBuilder
,那么需要完成的内存拷贝要less得多。 使用StringBuilder(int capacity)
你可以提高性能,如果你能估计最终的String
将会有多大。 即使你不精确,你可能只需要增加StringBuilder
的容量几次,这也可以提高性能。
在使用StringBuilder
实例的EnsureCapacity(int capacity)
方法调用之前,我已经看到了显着的性能提升,然后将其用于任何string存储。 我通常在实例化后在代码行上调用它。 它具有相同的效果,如果你像这样实例化StringBuilder
:
var sb = new StringBuilder(int capacity);
这个调用会提前分配所需的内存,这会在多个Append()
操作中导致更less的内存分配。 你必须猜测你需要多less内存,但对于大多数应用程序来说,这不应该太难。 我通常会犯一点太多的记忆(我们正在谈论1k左右)。
除了以前的答案之外,当我考虑这样的问题时,我总是会做的第一件事就是创build一个小testing应用程序。 在这个应用程序内部,对两种情况执行一些时间testing,并查看哪一个更快。
恕我直言,追加500 +string条目应该肯定使用StringBuilder。
String和StringBuilder实际上都是不可变的,StringBuilder内置了缓冲区,可以更有效地pipe理其大小。 当StringBuilder需要resize的时候,它被重新分配在堆上。 默认情况下它的大小为16个字符,你可以在构造函数中设置它。
例如。
StringBuilder sb = new StringBuilder(50);
string连接将花费更多。 在Java中,您可以根据需要使用StringBuffer或StringBuilder。 如果你想要一个同步的和线程安全的实现,去StringBuffer。 这将比string连接更快。
如果你不需要同步或线程安全的实现,去StringBuilder。 这将比string连接更快,也比StringBuffer更快,因为它们不会造成同步化开销。
StringBuilder可能是可取的。 原因是它分配了比当前需要更多的空间(你设置了字符的数量)为将来的追加留下空间。 那么那些适合当前缓冲区的未来追加不需要任何内存分配或垃圾回收,这可能是昂贵的。 一般来说,我使用StringBuilder进行复杂的string联合或多格式化,然后在数据完成时将其转换为正常的string,并且我需要一个不可变的对象。
如果你正在做很多string连接,使用一个StringBuilder。 当与一个string连接时,每次创build一个新的string,占用更多的内存。
亚历克斯
一般来说,如果我不得不多次设置string的值,或者如果有任何附加的string,那么它需要是一个string生成器。 我已经看到了我以前写过的应用程序,然后才学习了一些string构build器,这些string构build器拥有巨大的内存占用空间,而这些内存空间似乎还在不断增长。 更改这些程序以使用string生成器会显着减less内存使用量。 现在我发誓的stringbuild设者。
我的方法一直是在连接4个或更多string时使用StringBuilder,或者当我不知道如何进行连接时。
在这里有很好的性能相关文章
StringBuilder
效率要高得多,但是除非你做了大量的string修改,否则你不会看到这个性能。
以下是一段代码,以提供一个性能的例子。 正如你所看到的,当你进入大型迭代时,你真的只会看到性能提升。
正如你所看到的,200,000次迭代需要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();
以上代码的结果:
开始string+在28/01/2013 16:55:40。
完成string+在28/01/2013 16:55:40。
开始string+在28/01/2013 16:55:40。
完成string+在28/01/2013 16:56:02。
开始Sb追加在28/01/2013 16:56:02。
完成的Sb追加在28/01/2013 16:56:02。
从内存的angular度来看,StringBuilder会performance得更好。 至于处理,执行时间的差异可以忽略不计。