比在某些情况下,Foreach快得多吗?

问题描述:

我不喜欢过早的优化,但我很好奇,而做一个简单的任务 所以我添加了一个秒表。 我不明白差异如何如此之大。比在某些情况下,Foreach快得多吗?

每个字符串数组(7个字符)[richtextbox.text]。

排列长度:5500个元素。

的foreach执行时间:0.0015秒

对于执行时间:9.757秒

为:

if (chkLineBreaks.Checked) 
{ 
    for (int i = 0; i < txtInput.Lines.Length; i++) 
    { 
     outputStringBuilder.Append([email protected]"'{txtInput.Lines[i]}',"); 
    } 
} 

的foreach:

foreach (var line in txtInput.Lines) 
{ 
    outputStringBuilder.Append([email protected]"'{line}',"); 
    if (chkLineBreaks.Checked) 
     outputStringBuilder.AppendLine(); 
} 

从我读过的差异应该可以忽略不计,而且会稍微快一点。

更有甚者,在foreach在每次迭代的条件(除非它被“吊”起来循环之前

这到底是怎么回事

编辑:? 我已经改变了的foreach代码:

int i = 0; 
foreach (var line in txtInput.Lines) 
{ 
    outputStringBuilder.Append([email protected]"'{txtInput.Lines[i]}',"); 
    i++; 
} 

所以现在正在做同样的事情 它正在4.625秒 ..仍有约一半的时间用于

而且我知道,我可以提取外循环数组,但是这不是我测试在这里:)

编辑#2: 这是该节的整个代码:

Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     // for (int i = 0; i < txtInput.Lines.Length; i++) 
     // { 
     //  outputStringBuilder.Append([email protected]"'{txtInput.Lines[i]}',"); 
     // } 
     int i = 0; 
     foreach (var line in txtInput.Lines) 
     { 
      outputStringBuilder.Append([email protected]"'{txtInput.Lines[i]}',"); 
      i++; 
     } 
     MessageBox.Show(sw.Elapsed.ToString()); 
+0

你可能也想尝试保存'txtInput.Lines.Length'给一个变量,然后使用该变量的条件部分的for循环。看看这是如何影响性能的。 –

+1

9秒来自某些与for/foreach无关的东西。可能是一些UI线程编组问题。还要注意这两个测试不相同,因为在foreach的情况下,你还要检查chkLineBreaks.Checked。 –

+2

代码中有太多的差异来得出任何真正的结论。如果你真的想要比较,除了'for'和'foreach'之外,这两段代码完全一样。 – jdweng

问题是txtInput.Lines正在for循环中执行多次(每行一次)(由于使用了txtInput.Lines[i])。 因此,对于文件的每一行,您都会说'好的,请将此文本框解析为多行 - 然后让我排第n行 - 解析就是杀手锏。

一个更公平的比较:

if (chkLineBreaks.Checked) 
{ 
    var lines = txtInput.Lines; 
    for (int i = 0; i < lines.Length; i++) 
    { 
     outputStringBuilder.Append([email protected]"'{lines[i]}',"); 
    } 
} 

这样的Lines调用完成一次(即相当于foreach场景)。

发现这些问题的一种方法是比较时间。慢速的比慢速的慢6K,并且你有5.5K的条目。由于5.5K和6K是非常相似的数字,它可能会提示你想'我在循环中做什么,我真的不应该这样做?'

+0

我已经改变了foreach是相同的 - 请检查编辑。 – AngelicCore

+1

@AngelicCore:这仍然不是一回事。 'foreach'调用'txtInput.Lines.GetEnumerator()',它只评估'.Lines'一次。 'for'必须一遍又一遍地评估'.Lines',除非你将循环改为mjwills的建议。 –

+1

做了什么你问 - 现在回到0.001秒FOR – AngelicCore

编译后的代码在遍历数组(或列表)时看到forforeach语句之间的差异非常小。

考虑一个简单的代码写出来的字符串列表三种不同的方式:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var list = Enum.GetNames(typeof(System.UriComponents)); 

     // 1. for each 
     foreach (var item in list) 
     { 
      Console.WriteLine(item); 
     } 
     // 2. for loop 
     for (int i = 0; i<list.Length; i++) 
     { 
      Console.WriteLine(list[i]); 
     } 
     // 3. LINQ 
     Console.WriteLine(string.Join(Environment.NewLine, list)); 
    } 
} 

现在看MSIL编译代码,翻译回C#使用ILSpyDotNetPeek

// ConsoleApplication1.Program 
private static void Main(string[] args) 
{ 
    string[] list = Enum.GetNames(typeof(UriComponents)); 
    string[] array = list; 
    for (int j = 0; j < array.Length; j++) 
    { 
     string item = array[j]; 
     Console.WriteLine(item); 
    } 
    for (int i = 0; i < list.Length; i++) 
    { 
     Console.WriteLine(list[i]); 
    } 
    Console.WriteLine(string.Join(Environment.NewLine, list)); 
} 

查看两个for循环。编译器将foreach语句变为for循环。就string.Join()语句而言,它将调用SZArrayEnumerator,它包含对数组的引用和当前索引值。在每个.MoveNext()调用索引增加并返回一个新的值。基本上,它等同于以下内容:

int i = 0; 
while (i<list.Length) 
{ 
    Console.WriteLine(list[i]); 
    i++; 
}