StringBuilder
是如何工作的?
它在内部做了什么?它是否使用了不安全的代码?为什么它比+
操作符更快?
StringBuilder
是如何工作的?
它在内部做了什么?它是否使用了不安全的代码?为什么它比+
操作符更快?
当你使用 + 操作符来构建字符串时:
string s = "01";
s += "02";
s += "03";
s += "04";
在第一次连接时,我们创建了一个长度为四的新字符串,并将“01”和“02”复制到其中--复制了四个字符。在第二次连接中,我们创建了一个长度为六的新字符串,并将“0102”和“03”复制到其中--复制了六个字符。在第三次连接中,我们创建了一个长度为八的新字符串,并将“010203”和“04”复制到其中--复制了八个字符。到目前为止,这个包含八个字符的字符串已经复制了4 + 6 + 8 = 18个字符。继续进行。
...
s += "99";
第98次连接操作时,我们生成一个长度为198的字符串,将"010203...98"和"99"复制到其中。这使得我们总共需要4+6+8+...+198个字符来生成这个字符串。string s = "01" + "02" + "03" + "04"
,它会编译成 string s = string.Concat("01","02","03","04")
吗?(实际上我认为编译器会将其优化为 string s = "01020304"
,但如果所有的字符串值都不是硬编码的,它会使用 String.Concat 吗?) - NickStringBuilder
的实现在不同版本之间有所改变。但基本原理是保持一种可变的数据结构。我认为它过去使用的是一个仍在被修改的字符串(使用内部方法),并确保在返回后它不会再被修改。
使用 StringBuilder
而非字符串拼接 循环中 更快的原因,正是由于其可变性 - 每次修改后不需要构建新的字符串,这意味着不需要复制字符串中的所有数据等。
对于单个字符串连接而言,使用 +
实际上比使用 StringBuilder
稍微更有效率。只有当您执行 多个 操作时,并且您不需要中间结果时,StringBuilder
才会表现出色。
有关更多信息,请参见我的关于 StringBuilder
的文章。
微软CLR确实使用内部调用进行一些操作(与不安全代码不完全相同)。与一堆连接的字符串相比,最大的性能优势在于它将内容写入char[]
,并且不会创建太多中间字符串。当您调用ToString()时,它会从您的内容构建一个完成的、不可变的字符串。
stringBuilder.Remove(1023, 2000)
,那会怎么样?如果你有一个字符串的链表,那就是一个复杂的算法。我相信这不会很有效率。但是,如果你知道自己不需要插入、删除、替换等功能,可以随意实现自己的LLStringBuilder类。 - agent-jnew StringBuilder(2048*1024)
,您可以指定足够大的初始容量,从而最小化重新调整大小的成本。(您可能已经知道了这一点,但它可能会使未来的读者受益。) - agent-jstr += ",";
编译成这样:
str = String.Concat(str, ",");
RefSrcDirectory\Source\.Net\4.0\DEVDIV_TFS\Dev10\Releases\RTMRel\ndp\clr\src\BCL\System\Text\StringBuilder.cs\1305376
路径下有一份带注释的StringBuilder.cs
副本。我列出的目录结构可能与参考源代码中的不完全相同,而且只适用于 .Net 4.0。 - Brian