2017-10-29 38 views
0

我不喜歡過早的優化,但我很好奇,而做一個簡單的任務 所以我添加了一個秒錶。 我不明白差異如何如此之大。比在某些情況下,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

回答

3

問題是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

1

編譯後的代碼在遍歷數組(或列表)時看到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++; 
} 
相關問題