2009-12-13 35 views
2

奇怪*的問題,我有這樣的代碼:C#*用秒錶和foreach循環

var options = GetOptions(From, Value, SelectedValue);  
var stopWatch = System.Diagnostics.Stopwatch.StartNew(); 

foreach (Option option in options) 
{ 
    stringBuilder.Append("<option"); 

    stringBuilder.Append(" value=\""); 
    stringBuilder.Append(option.Value); 
    stringBuilder.Append("\""); 

    if (option.Selected) 
     stringBuilder.Append(" selected=\"selected\""); 

    stringBuilder.Append('>'); 

    stringBuilder.Append(option.Text); 
    stringBuilder.Append("</option>"); 
} 

HttpContext.Current.Response.Write("<b>" + stopWatch.Elapsed.ToString() + "</b><br>"); 

它寫着:
00:00:00.0004255第一次嘗試(不調試)
00 :00:00.0004260第二次嘗試和
00:00:00.0004281第三次嘗試。現在

,如果我更改代碼,使該措施將是 foreach循環:

var options = GetOptions(From, Value, SelectedValue);  

foreach (Option option in options) 
{ 
    var stopWatch = System.Diagnostics.Stopwatch.StartNew(); 

    stringBuilder.Append("<option"); 

    stringBuilder.Append(" value=\""); 
    stringBuilder.Append(option.Value); 
    stringBuilder.Append("\""); 

    if (option.Selected) 
     stringBuilder.Append(" selected=\"selected\""); 

    stringBuilder.Append('>'); 

    stringBuilder.Append(option.Text); 
    stringBuilder.Append("</option>"); 

    HttpContext.Current.Response.Write("<b>" + stopWatch.Elapsed.ToString() + "</b><br>"); 
} 

...我得到
[00:00:00.0000014,00:00:00.0000011] = 00:00:00.0000025(未進行調試),
[00:00:00.0000016,00:00:00.0000011] = 00:00:00.0000027在第二次嘗試中,
[00:00:00.0000013 ,00:00:00.0000011] = 00:00:00.0000024。

?!
根據第一個結果完全是廢話......我聽說foreach循環很慢,但從來沒有想到,它是所以慢......是這樣嗎?

options有2個選項。 這裏的option類,如果需要的話:

public class Option 
{ 
    public Option(string text, string value, bool selected) 
    { 
     Text = text; 
     Value = value; 
     Selected = selected; 
    } 

    public string Text 
    { 
     get; 
     set; 
    } 

    public string Value 
    { 
     get; 
     set; 
    } 

    public bool Selected 
    { 
     get; 
     set; 
    } 
} 

感謝。

+0

那實際上是什麼問題?是「爲什麼情況2時鐘比情況1快?」或者是「爲什麼'foreach'循環如此緩慢?」 –

+0

爲什麼情況2的時鐘比情況1快了 –

+0

@Alon:我明白了,所以你問爲什麼迭代通過foreach循環(不包括循環中的操作)非常慢?是啊? –

回答

7

foreach循環本身與時差無關。

什麼是GetOptions方法返回?我的猜測是,它不是返回一組選項,而是一個能夠獲取選項的枚舉器。這意味着,直到你開始迭代它們時,纔會實際獲取選項。

在第一種情況下,您在開始迭代選項之前啓動時鐘,這意味着獲取選項的時間包含在時​​間中。

在第二種情況下你正在之後開始所述時鐘開始迭代的選項,這意味着用於獲取選項的時間是不包括在時間。

因此,您看到的時間差異並非歸因於foreach循環本身,而是獲取選項所需的時間。

可以確保該選項立即獲取通過讀取它們到一個集合:

var options = GetOptions(From, Value, SelectedValue).ToList(); 

現在衡量性能,你會看到差別很小。

0

第一個代碼示例不會輸出任何內容,直到所有選項都被迭代,而第二個代碼示例在第一個選項被處理後輸出一個時間時纔會輸出任何內容。如果有多種選擇,你會期望看到這樣的差異。

+0

在第二個代碼示例中,我寫了每個選項在每次嘗試中花費了多少時間,並且它遠離第一個代碼示例結果。 –

+0

什麼類型是選項? foreach將創建一個需要處理的枚舉器。處置可能會燃燒一些cpu循環。 – recursive

+0

選項是IEnumerable

1

如果您測量執行160次所花費的時間,它通常會比測量執行一次花費的時間長160倍。你是在暗示循環的內容只執行一次,還是你想比較粉筆和奶酪?

在第一種情況下,嘗試使用 stopWatch.Elapsed.ToString() 到 stopWatch.Elapsed.ToString()/ options.Count

更改代碼的最後一行,將在至少平均您將一次迭代與一次迭代進行比較。

但是,您的結果仍然是無用的。一次很短的操作時間會導致較差的結果 - 您必須重複這種操作數萬次以獲得統計意義上的平均時間。否則,系統時鐘的不準確性以及啓動和停止定時器所涉及的開銷會使搜索結果變差。

此外,當所有這些情況發生時,PC在做什麼?如果還有其他進程正在加載CPU,那麼他們很容易干擾你的時間。如果您在繁忙的服務器上運行此操作,那麼您可能會得到有競爭力的隨機結果。

最後,你如何優化測試可以改變事情。如果您始終運行測試1,然後測試2,則可能運行第一個測試會影響CPU高速緩存(例如,的選項列表中的數據)等,以便下面的代碼能夠更快地執行。如果垃圾收集發生在你的一個測試中,它會扭曲結果。

您需要消除所有這些因素,然後纔能有值得比較的數字。那麼你應該問「爲什麼測試1比測試2慢得多」?

0

只需pause it a few times in the IDE你會看到時間的推移。

有一種非常自然和強烈的誘惑力,認爲事情需要的時間與他們的代碼量成正比。例如,你認爲哪個更快?

for (MyClass x in y) 

for (MyClass theParticularInstanceOfClass in MyCollectionOfInstances) 

很自然地認爲,首先是速度更快,而實際上代碼大小是無關緊要的,可能藏匿昂貴的操作,衆說紛紜。