2010-11-03 82 views
0
  Stopwatch sw = new Stopwatch(); 
      for (int i = 0; i < lines.Length; i++) 
      { 
       sw.Start(); 
       fn(); //call function 
       sw.Stop(); 

      } 
      Console.WriteLine(sw.ElapsedMilliseconds); 


      long total =0; 
      for (int i = 0; i < lines.Length; i++) 
      { 
       Stopwatch sw = Stopwatch.StartNew(); 
       fn(); //call function 
       sw.Stop(); 
       total += sw.ElapsedMilliseconds; 

      } 
      Console.WriteLine(total); 

輸出是不一樣的,你有沒有任何解釋?秒錶怪異的行爲

+0

對於任何合理長度的fn()(一個值得分析),與循環相關的開銷將可以忽略不計,並且在任何情況下都小於與開始和停止相關的開銷。首先,Start和Stop都有方法調用開銷(假設沒有內聯),而簡單的for循環只是一個增量和比較分支。 – 2010-11-03 16:05:57

回答

8

撇開之類的東西,你在第二循環中創建對象的負荷,從而易引起內fn()或別的東西垃圾收集的事實實際上使計時的同時,你也只是它需要更長的時間在第二種情況下每次迭代採用已經過去的毫秒

假設每次迭代需要0.1毫秒。您的第二個循環的總數將爲0,因爲在每次迭代時,它會將經過時間舍入爲0毫秒。第一個循環記錄了經過的記號

把所有這些放在一邊,你不應該頻繁地啓動和停止計時器 - 它會將與你的結果混淆在一起。相反,在循環之前啓動一次秒錶,並在循環之後停止。

如果要取出循環的開銷,只需簡單地計時空循環以查找開銷,然後從包含實際工時的循環中花費的時間中減去該開銷。現在它不是真的相當這很簡單,因爲現實世界的CPU的各種複雜性 - 事情如緩存未命中 - 但微型基準化坦率地說從來沒有在這方面特別準確。它應該比其他任何東西都用作指南。

+0

我想我現在明白了這個行爲,謝謝 – 2010-11-03 16:08:04

+0

現在這已經很老了,但我認爲值得注意的是,這裏的秒錶的典型用法是在*循環之前開始*停止*循環之後再除以迭代(lines.Length)來獲得fn()的平均時間。假設迭代次數很高,考慮到循環的低開銷,這應該相當準確,並且對於非常快速的函數,您不會遇到秒錶粒度問題。 – Lummo 2012-10-24 06:20:39

+0

@Lummo:我已經添加了一個這樣的句子。 – 2012-10-24 06:23:15

4

因爲StartNew()Stop()會產生開銷。這就是您通常以100或1000次迭代進行這些測試的原因:最小化實際性能測量的性能開銷。

+0

我認爲這個問題是由於Skeet提到的丟失分辨率造成的 – 2010-11-03 16:07:10

+0

創建超出了測量代碼(秒錶上的開始是StartNew中完成的最後一件事),因此不影響計時器。解決方案和四捨五入似乎是原因。正確的答案似乎是Jon Skeets答案(http://stackoverflow.com/a/4088847/95008)。 – Spiralis 2012-09-07 11:51:11

1

您可能正在運行系統計時器的粒度。有時計時一個微不足道的函數將返回0或10毫秒。這個錯誤可能會加在你的測試上。

如果您運行第一個循環兩次或第二個循環兩次,您可能會看到類似的結果。

1

該循環的開銷將比重複停止/啓動計時器的開銷要小得多,並且在重複創建新計時器時會更少。因此,我會在循環之前啓動計時器,並在循環之後結束計時器,並將迭代次數除以經過的時間。它會給你更準確的結果。

+0

這是真的,但我想只測量我的功能性能 – 2010-11-03 15:52:34

+0

然後,如Jon所說,測量一個空循環並從這個測量中減去。 – spender 2010-11-03 15:53:52