比在某些情况下,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());
问题是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是非常相似的数字,它可能会提示你想'我在循环中做什么,我真的不应该这样做?'
我已经改变了foreach是相同的 - 请检查编辑。 – AngelicCore
@AngelicCore:这仍然不是一回事。 'foreach'调用'txtInput.Lines.GetEnumerator()',它只评估'.Lines'一次。 'for'必须一遍又一遍地评估'.Lines',除非你将循环改为mjwills的建议。 –
做了什么你问 - 现在回到0.001秒FOR – AngelicCore
编译后的代码在遍历数组(或列表)时看到for
和foreach
语句之间的差异非常小。
考虑一个简单的代码写出来的字符串列表三种不同的方式:
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#
使用ILSpy
或DotNetPeek
。
// 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++;
}
你可能也想尝试保存'txtInput.Lines.Length'给一个变量,然后使用该变量的条件部分的for循环。看看这是如何影响性能的。 –
9秒来自某些与for/foreach无关的东西。可能是一些UI线程编组问题。还要注意这两个测试不相同,因为在foreach的情况下,你还要检查chkLineBreaks.Checked。 –
代码中有太多的差异来得出任何真正的结论。如果你真的想要比较,除了'for'和'foreach'之外,这两段代码完全一样。 – jdweng