[英]Top 100 values in a Dictionary<string, int> - Why is LinQ so much faster than a foreach loop
[英]Foreach MUCH faster than For in some cases?
我不喜歡過早的優化,但是在做一個簡單的任務時很好奇,所以我添加了秒表。 我不明白差別有多大。
每個[richtextbox.text]的字符串數組(7個字符)。
數組長度:5500個元素。
每次經過時間: 0.0015秒
經過的時間: 9.757秒
對於:
if (chkLineBreaks.Checked)
{
for (int i = 0; i < txtInput.Lines.Length; i++)
{
outputStringBuilder.Append($@"'{txtInput.Lines[i]}',");
}
}
的foreach:
foreach (var line in txtInput.Lines)
{
outputStringBuilder.Append($@"'{line}',");
if (chkLineBreaks.Checked)
outputStringBuilder.AppendLine();
}
從我閱讀的內容來看,差異應該可以忽略不計,For的速度會稍快一些。
更重要的是,foreach在每次迭代中都有一個條件(除非在循環之前將其“吊起”)。
這里發生了什么?
編輯:我已經將foreach代碼更改為:
int i = 0;
foreach (var line in txtInput.Lines)
{
outputStringBuilder.Append($@"'{txtInput.Lines[i]}',");
i++;
}
因此,它現在正在做同樣的事情。 FOR仍需要4.625秒的時間。
我也知道我可以在循環外提取數組,但這不是我在這里測試的內容:)
編輯#2:這是該部分的全部代碼:
Stopwatch sw = new Stopwatch();
sw.Start();
// for (int i = 0; i < txtInput.Lines.Length; i++)
// {
// outputStringBuilder.Append($@"'{txtInput.Lines[i]}',");
// }
int i = 0;
foreach (var line in txtInput.Lines)
{
outputStringBuilder.Append($@"'{txtInput.Lines[i]}',");
i++;
}
MessageBox.Show(sw.Elapsed.ToString());
問題是txtInput.Lines
在for
循環中執行了很多次(每行一次)(由於使用txtInput.Lines[i]
)。 因此,對於文件的每一行,您說的是“好的,請將該文本框解析為多行-然后讓我進入第n行”,而解析是殺手bit。
為了更公平的比較:
if (chkLineBreaks.Checked)
{
var lines = txtInput.Lines;
for (int i = 0; i < lines.Length; i++)
{
outputStringBuilder.Append($@"'{lines[i]}',");
}
}
這樣, Lines
調用僅執行一次(即相當於foreach
方案)。
發現此類問題的一種方法是比較時間安排。 慢速的速度比快速的速度慢大約6K,並且您有5.5K條目。 由於5.5K和6K是非常相似的數字,因此它可能會提示您思考:“我是否正在循環中做某些我本不應該做的事情?”
在遍歷數組(或列表)時, 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
編譯的代碼,使用ILSpy
或DotNetPeek
將其轉換回C#
。
// 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));
}
請參閱兩個循環。 foreach
語句成為編譯器的for
循環。 就string.Join()
語句而言,它調用SZArrayEnumerator
,它包含對數組的引用以及當前索引值。 在每次.MoveNext()
調用時,索引都會遞增,並返回一個新值。 基本上,它等效於以下內容:
int i = 0;
while (i<list.Length)
{
Console.WriteLine(list[i]);
i++;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.