StringBuilder在C#中的性能?
我有一个StringBuilder在C#中的性能?,c#,C#,我有一个StringBuilder对象,我在其中添加了一些字符串,如下所示: 我想知道哪种方法更好,首先是: StringBuilder sb = new StringBuilder(); sb.Append("Hello" + "How" + "are" + "you"); 第二个是: StringBuilder sb = new StringBuilder(); sb.Append("Hello").Append("How").Append("are").Append("you"); 第
StringBuilder
对象,我在其中添加了一些字符串,如下所示:
我想知道哪种方法更好,首先是:
StringBuilder sb = new StringBuilder();
sb.Append("Hello" + "How" + "are" + "you");
第二个是:
StringBuilder sb = new StringBuilder();
sb.Append("Hello").Append("How").Append("are").Append("you");
第一种方法效率更高。编译器将其转换为以下单个调用:
StringBuilder sb = new StringBuilder();
sb.Append("HelloHowareyou");
衡量绩效
知道哪个更快的最好方法是测量它。我要直截了当地说:以下是结果(时间越短意味着速度越快):
给定的数字是在紧循环中执行1亿次操作的秒数
结论
- 最快的是使用字符串文字和
+
- 但是如果您有变量,那么使用
比追加
更快。由于额外调用了+
,第一个版本的速度较慢String.Concat
如果您想自己测试,下面是我用来获取上述计时的程序:
using System;
using System.Text;
public class Program
{
public static void Main()
{
DateTime start, end;
int numberOfIterations = 100000000;
start = DateTime.UtcNow;
for (int i = 0; i < numberOfIterations; ++i)
{
StringBuilder sb = new StringBuilder();
sb.Append("Hello" + "How" + "are" + "you");
}
end = DateTime.UtcNow;
DisplayResult("sb.Append(\"Hello\" + \"How\" + \"are\" + \"you\")", start, end);
start = DateTime.UtcNow;
for (int i = 0; i < numberOfIterations; ++i)
{
StringBuilder sb = new StringBuilder();
sb.Append("Hello").Append("How").Append("are").Append("you");
}
end = DateTime.UtcNow;
DisplayResult("sb.Append(\"Hello\").Append(\"How\").Append(\"are\").Append(\"you\")", start, end);
string a = "Hello";
string b = "How";
string c = "are";
string d = "you";
start = DateTime.UtcNow;
for (int i = 0; i < numberOfIterations; ++i)
{
StringBuilder sb = new StringBuilder();
sb.Append(a + b + c + d);
}
end = DateTime.UtcNow;
DisplayResult("sb.Append(a + b + c + d)", start, end);
start = DateTime.UtcNow;
for (int i = 0; i < numberOfIterations; ++i)
{
StringBuilder sb = new StringBuilder();
sb.Append(a).Append(b).Append(c).Append(d);
}
end = DateTime.UtcNow;
DisplayResult("sb.Append(a).Append(b).Append(c).Append(d)", start, end);
Console.ReadLine();
}
private static void DisplayResult(string name, DateTime start, DateTime end)
{
Console.WriteLine("{0,-60}: {1,6:0.000}s", name, (end - start).TotalSeconds);
}
}
使用系统;
使用系统文本;
公共课程
{
公共静态void Main()
{
日期时间开始,结束;
int numberOfIterations=100000000;
开始=DateTime.UtcNow;
对于(int i=0;i
在当前示例中,字符串文字:
"Hello" + "How" + "are" + "you"
将由编译器编译为一个常量字符串文字,因此在技术上比:
sb.Append("Hello").Append("How").Append("are").Append("you");
但是,如果要使用字符串变量:
sb.Append(s1 + s2 + s3 + s4);
然后,后者会更快,因为前者可能会在将最终字符串传递到Append
方法之前创建一系列字符串(由于串联),而后者则会避免额外的字符串创建(但会权衡额外的方法调用和内部缓冲区大小调整)
更新:为了进一步说明,在只有4个项目被连接的情况下,编译器将发出对
String.Concat(String,String,String,String)
的调用,知道字符串的长度和数量将比StringBuilder
更有效。在第一种情况下,编译器将构造单个字符串,因此只需调用Append一次。然而,我怀疑这会有很大的不同。你的测量结果显示了什么?第二种方法更好。字符串是不可变的,这意味着当您使用sb.Append(“Hello”+“How”+“are”+“you”)时,您正在创建字符串的多个副本
e、 g
然后
然后
等等
第二段代码的性能要好得多
编辑:当然这没有考虑到编译器的优化,但最好按预期使用该类
正如人们所指出的,由于这些是文本,编译器会对这些操作进行优化——但我的观点是,字符串连接是StringBuilder试图避免的事情
例如,循环多次:
var someString = "";
foreach (var s in someListOfStrings)
{
someString += s;
}
不如做:
var sb = new StringBuilder();
foreach(var s in someListOfStrings)
{
sb.Append(s);
}
sb.ToString();
因为这可能会更快,因为正如我前面所说的,字符串是不可变的
我认为OP是在谈论使用连接,因为
sb.Append("Hello" + "How");
似乎完全没有意义的时候
sb.Append("HelloHow");
会更符合逻辑吗
在我看来,在OPs的思想中,占位符文本最终将成为一堆变量…编译器将在编译时连接字符串常量。如果连接的字符串表达式不超过四个,编译器将发出对
string.Concat
s + t + u + v ==> String.Concat(s, t, u, v)
这比StringBuilder
执行得更快,因为StringBuilder
可能需要调整其内部缓冲区的大小,而Concat
可以提前计算总的结果长度。但是,如果预先知道结果字符串的最大长度,则可以通过指定初始工作缓冲区大小来初始化StringBuilder
var sb = new StringBuilder(initialBufferSize);
StringBuilder
通常用于循环和其他动态场景中,在这种情况下执行速度比s+=t
快。请参阅。这已经涵盖到了死亡:-)你会发现有趣的我的问题是-为什么你会想做“你好”+“如何”等,当“你好”会很好?这个问题的真正意义是什么?因为我的答案因为技术原因而遭到抨击,我认为这不是问题的关键……你是
sb.Append("Hello" + "How");
sb.Append("HelloHow");
s + t + u + v ==> String.Concat(s, t, u, v)
var sb = new StringBuilder(initialBufferSize);