2014-09-30 41 views
1

我想了解爲什麼在循環中的first iteration比其餘的更快。爲什麼第一次迭代總是比下一個循環更快?

Stopwatch sw = new Stopwatch(); 
sw.Start(); 

for(int i=0; i<10; i++) 
{ 
    System.Threading.Thread.Sleep (100); 
    Console.WriteLine ("Finished at : {0}", ((double) sw.ElapsedTicks/Stopwatch.Frequency) * 1e3); 
} 

當我執行的代碼,我得到如下:

enter image description here

起初我以爲這可能是由於Stopwatch類的準確率,但後來爲什麼它僅適用於第一個元素?糾正我,如果我失去了一些東西。

+2

幾乎沒有那麼慢? – Ric 2014-09-30 15:13:10

+0

它實際上是一個跳躍和增量執行每一步,除了第一個。 – Maku 2014-09-30 15:14:36

+0

我真的沒有看到區別。循環中的每次迭代大約需要100ms! – 2014-09-30 19:39:15

回答

7

這是一個非常有缺陷的基準。首先,Thread.Sleep並不能保證你會睡100毫秒。嘗試更長時間的睡眠,你會看到更一致的結果。

所以它可能只是調度 - 下一次迭代總是在睡眠後進行睡眠。由於Sleep工作得益於系統中斷時鐘,因此第一次之後的睡眠應該花費相似的時間,而第一次必須首先與時鐘「同步」。

如果您在之前添加另一個睡眠(在開始秒錶之前),您可能會在每次迭代中獲得更近的時間。

或者更好,不要用睡覺。如果你使用一些實際的CPU工作,你可以避免線程切換(假設你有足夠的CPU來完成這些工作)以及其他許多與循環本身無關的成本。例如,

Stopwatch sw = new Stopwatch(); 
sw.Start(); 

for(int i=0; i<10; i++) 
{ 
    Thread.SpinWait(10000000); 

    Console.WriteLine ("Finished at : {0}", ((double) sw.ElapsedTicks/Stopwatch.Frequency) * 1e3); 
} 

這會給你更一致的結果,因爲它根本不依賴於時鐘。

還有很多其他的事情可能會使這樣的基準複雜化,這就是爲什麼基準測試不是這樣做的原因。總會有偏差,而且他們會變得相當大,特別是在一個有很多工作的系統上。

換句話說,如果你在毫秒量級上獲得CPU工作執行時間的差異,有人正在竊取你的工作。現代CPU中沒有任何東西可以解釋僅僅基於如此巨大的差異。 i++在那裏或沒有。

我可以用你的代碼描述更多的問題,但它可能不值得。就谷歌來說,在C#中的CPU工作基準測試的一些最佳實踐,你會得到更多的價值。

呵呵,只是爲了幫助在家裏更多的點擊我的計算機,第一個趨向於從99100。這是非常不尋常的,因爲默認值是15.6ms,而不是1ms,但罪魁禍首很容易找到 - Chrome會將其設置爲1ms。哎喲。

+0

這是* NOT *上述代碼給出的結果給出的原因。這是因爲'Stopwatch'沒有被重置......它只是不斷增加從以前所有迭代中消耗的時間越來越多的時間.. 。迭代值'100,200,300,400,500 ...'清楚地表明..這是由於睡眠等的準確性和定時器分辨率所導致的答案根本不適用於此。 – 2014-09-30 15:32:55

+2

@VikasGupta等等,你認爲OP沒有指出*那個* out?他特別挑出了* first *迭代,而不是之後的每個迭代更慢更慢。我們正在談論的是毫秒之差,而不是數百。 – Luaan 2014-09-30 15:35:16

+0

我可能沒有閱讀你正在閱讀的問題..我再次閱讀它。如果你的解釋是正確的,桑可以告訴..和測試輸出一起的問題肯定會誤導我。 – 2014-09-30 15:41:29

3

你輸出的次數是合計自開始以來的時間。所以,時間增加大約100ms正是你應該期待的

但是,當你使用Thread.Sleep你放棄了對線程的控制,並且可能接近你指定的時間。那個時間是系統量程的倍數 - 所以,你指定的不可能是準確的。如果其他優先級更高的線程正在開展工作,那麼您的線程處理器時間的可能性就不大可能接近您建議的時間。

相關問題