C# foreach中的Stringbuilder比for中的要慢,String.Join()在集合中很糟糕?
在这里看到一个关于连接字符串的问题后,我做了一些测试,并了解到在foreach中连接字符串比使用for循环和使用数组中的索引要慢。for循环不应该因为数组上的绑定检查而变慢吗?(对foreach上不存在的字符串[i]进行绑定检查) 另一件我不明白的事情是string.Join()在列表中的慢度 编辑:将错误和更新源更新为最终源(删除最后一个“,”) 以下是测试结果: 以下是资料来源:C# foreach中的Stringbuilder比for中的要慢,String.Join()在集合中很糟糕?,c#,arrays,performance,string,C#,Arrays,Performance,String,在这里看到一个关于连接字符串的问题后,我做了一些测试,并了解到在foreach中连接字符串比使用for循环和使用数组中的索引要慢。for循环不应该因为数组上的绑定检查而变慢吗?(对foreach上不存在的字符串[i]进行绑定检查) 另一件我不明白的事情是string.Join()在列表中的慢度 编辑:将错误和更新源更新为最终源(删除最后一个“,”) 以下是测试结果: 以下是资料来源: public static void Main(string[] Args) { List<str
public static void Main(string[] Args)
{
List<string> strings = new List<string>() {};
for (double d = 0; d < 12000; d++) {
strings.Add(d.ToString());
}
GC.Collect();
GC.WaitForPendingFinalizers();
Performance(() =>
{
StringBuilder sb = new StringBuilder();
foreach (string s in strings)
{
sb.Append(s);
sb.Append(",");
}
sb.Remove(sb.Length - 1, 1);
}, "StringBuilder foreach");
GC.Collect();
GC.WaitForPendingFinalizers();
Performance(() =>
{
StringBuilder sb = new StringBuilder();
int max = strings.Count-1;
int i;
for (i = 0; i < max; i++)
{
sb.Append(strings[i]);
sb.Append(",");
}
sb.Append(strings[i]);
}, "StringBuilder for");
GC.Collect();
GC.WaitForPendingFinalizers();
Performance(() =>
{
string s = string.Join(",", strings);
}, "String.Join");
}
public static void Performance(Action fn, string prefix)
{
var timer = new Stopwatch();
timer.Start();
for (var i = 0; i < 10000; ++i)
{
fn();
}
timer.Stop();
Console.WriteLine("{0} {1} Time: {2}ms ({3})", prefix, fn.ToString(), timer.ElapsedMilliseconds, timer.ElapsedTicks);
}
它可能对数组有好处,但对集合字符串有好处。Join非常糟糕,对大字符串更是如此
如果您希望比较以下内容,仅供参考:
Windows 7 64bit
CPU Type QuadCore AMD Phenom II X4 945
CPU Clock 3000 MHz
L3 Cache 6 MB (On-Die, ECC, NB-Speed)
North Bridge Clock 2010.8 MHz
Memory 8190 MB
Memory Bus 804.3 MHz DDR3-1600
Motherboard Chipset AMD 790X, AMD K10
Memory Timings 8-9-9-24 (CL-RCD-RP-RAS)
Command Rate (CR) 1T
for循环不应该因为数组上的绑定检查而变慢吗
否,CLR可以将其优化为1检查是否可以验证边界。这使得
int max = strings.Count - 1;
一个糟糕的优化。在FX 1.1中,它会让您付出代价。(这也不正确)
foreach
需要做更多的工作(通过电子计算器)。请注意,差异很小 查看ILSpy中的IL代码
foreach循环有一个隐式try。。最后,for循环没有
在foreach内部还有对MoveNext的隐式调用。MoveNext有很多开销,包括在最终对列表执行索引操作以获取条目之前进行版本更改检查
理论上,foreach可以更快,但它显然比裸for循环做更多的工作
这是在vs2010下。不确定其他版本如何处理此问题 marjino,字符串不是值类型。或者你可以评论字符串的速度有多慢。Join在列表上-在数组上非常快。foreach涉及为集合创建枚举数实例,而for循环不涉及该实例。边界测试以某种方式涉及这两种操作。另外,
用于(int i=0;i字符串是引用类型。此外,您的for
循环结束得太早了一步。for循环测试缺少最后一个字符串。Tryint max=Strings.Count;
Hank int max=string.Count;是正确的,-1是一个错误,但int max会进行优化。使用我发布的新代码并尝试。foreach必须创建一个枚举数或者在每个for上,但是for必须对字符串[i]执行数百万次绑定检查除非编译器在那里做了一些魔术…但是你有一点需要编译器优化绑定检查。我尝试将int I;移出操作,它将for的速度降低了5%。因此必须对I变量进行一些优化。好的,我现在认为编译器无法像你所想的那样优化这个循环,因为选择超出了对其进行迭代的方法的范围(因此另一个线程可能会更改它),这就是为什么int max会进行优化(它会跳过每次迭代时读取属性)。@Marino:只需将属性内联留给JIT。这是一个老话题。
Windows 7 64bit
CPU Type QuadCore AMD Phenom II X4 945
CPU Clock 3000 MHz
L3 Cache 6 MB (On-Die, ECC, NB-Speed)
North Bridge Clock 2010.8 MHz
Memory 8190 MB
Memory Bus 804.3 MHz DDR3-1600
Motherboard Chipset AMD 790X, AMD K10
Memory Timings 8-9-9-24 (CL-RCD-RP-RAS)
Command Rate (CR) 1T
int max = strings.Count - 1;