2015-11-02 74 views
0

假設我們有一個類是這樣的:調用空行爲的性能影響是什麼?

public class Task 
{ 
     public Action PostAction=()=>{} 

     public void Do() 
     { 
      //Do Some Stuffs 
      PostAction(); 
     } 
} 

正如你可以看到PostAction是存在的,所以我們可以注入後的行動。

現在假設我們有一個任務列表,其中一些具有後行動,他們大多沒有,我們都是這樣美其名曰:

做空後的行動有任何性能影響執行上面的代碼?

+2

你可能比編寫這個問題的速度更快:-P – derape

回答

5

這常常會出現,因爲您的代碼在您引發事件時也必須進行空測試。抖動優化器無法做任何事情來優化無所事事的呼叫,它無法超越委託調用。這段代碼的快速版本,避免使委託調用:

public class Task { 
     public Action PostAction; 

     public void Do() { 
      if (PostAction != null) PostAction(); 
     } 
} 

繪製與System.Diagnostics.Stopwatch的區別是非常棘手的,代表調用是相當快的。我確保Do()調用不能通過賦予[MethodImpl(MethodImplOptions.Noinlining)]屬性來內聯。我不是非常快的筆記本電腦平均測量與移動的Haswell芯片:

  • 空DO():3.9納秒/調用
  • 空測試:4.3納秒/呼叫= 4.3 - 3.9〜= 0.4納秒
  • 調用:7.5納秒/呼叫= 7.5 - 3.9〜3.6 =納秒

當心的 「空DO()」 測量包括執行測試,一個用於(;;)環路的開銷以及使方法調用。這在所有測量中都是不變的開銷。

您可以告訴成本,委託調用比空測試(3.6 - 0.4)/ 0.4〜= 800%慢。如果你認爲不變的開銷是有代表性的(不是),你可以得到更友好的數字:(7.5 - 4.3)/ 4.3 - = 75%。你的foreach循環將會有更多的開銷,從而降低性能損失百分比。使用foreach迭代Enumerable.Range的測試(17.0 - 13.9)/ 13.9 - = 22%較慢。

這些當然是相當多的數字。但是,絕對值的數字非常低。如果你不經常打電話給委託人,或者有很多人(因此增加了不斷的開銷),那麼表演失敗就很難被注意到。

對於null的測試,正如演示如何引發事件的任何示例代碼所示,這是推薦的方法。如果您對代理將要被替換的期望很高(即事件將被訂閱),那麼您只有充分的理由使用lambda。在這種情況下,您優化了空檢查,每次調用節省大約一個CPU週期。

+0

我的指南在搜索優化掉這種東西之前首先有一個異形瓶頸,但在此添加另一個測試用例可能很有趣。使用新的C#6功能,[null-conditional](https://msdn.microsoft.com/en-us/library/dn986595.aspx)運算符:'public void Do(){PostAction?.Invoke() ; }' – Sehnsucht

相關問題