2011-11-30 82 views
0

我們在一個小測試應用程序中有非常有趣的效果,這是我們無法解釋的。c#的性能和可能的優化

我們的代碼塊:

while (true) 
{ 
    for (int i = 0; i < 1920; i++) 
    { 
     for (int j = 0; j < 1080; j++) 
     { 
      //l += rand.Next(j); 
      l += matcher.Next(j); 
     } 
    } 
    k++; 

    Console.WriteLine("{0}: Iteration {1}, l: {2}", DateTime.Now.ToString("hh:mm:ss"), k, l); 
    l = 0; 
    handle.WaitOne(100); 
} 

和類匹配器確實在其Next(j)電話只有一個東西。它返回其內部創建的Random對象的方法(所以,我們正在添加一個簡單的函數調用)。

這裏的匹配器類定義:

class Matcher 
{ 
    private Random rand = new Random(); 

    internal int Next(int j) 
    { 
     return rand.Next(j); 
    } 
} 

當我們執行該代碼一個迭代運行在Intel的Core 2 Quad約6秒。 但是,如果我們對行l += matcher.Next(j);發表評論,並將取消註釋行l += rand.Next(j);,則單次迭代開始花費大約第二次。

有沒有人有任何想法,爲什麼會發生?

+0

注意:這只是一個非常簡單的測試。該函數中的實際邏輯將更復雜 –

+0

使用'StopWatch'。 –

+0

您是否啓用優化(發佈配置)來運行測試? –

回答

3

它不只是一個簡單的函數調用,這也是發生在那裏的內部蘭特對象的間接引用。當你直接調用下一個隨機數時,JIT編譯器可以優化你的循環,但是當它在另一個類中時不會。

的函數被調用超過200萬次,這需要3微秒來評價。這不是世界上最快的功能,但也不是太慢,這是乘法效應殺死了性能。

如果匹配沒有鎖定,或者如果它是確定以創建它的多個副本,您可以通過並行你的算法,比如,八路您的酷睿2,四加快步伐。代碼應該在一秒之內完成。

+0

一個額外的(可能可升降的)解除引用和一個內聯的調用(使OP代碼可運行的最簡單的方法是在內聯大小限制內)不足以在每次調用時增加2.5μs,除非它們正在ZX81上運行。即使沒有提升或內聯它不會。 –

1

當然額外的通話需要一些時間(簡答:P)。爲什麼它很難說是6倍。在查看性能時,最好查看生成的IL(例如使用ILSpy),因爲編譯器可能會在一種情況下進行優化,而在另一種情況下可能無法進行優化。

在C#的端一行可編譯到不同IL指令,或甚至被翻譯成不同的本機代碼(以便運行在機器上更快,但在另一個更慢)。在某些情況下,垃圾收集器甚至可能是造成差異的原因。

+0

如果我們能看到C#,單單從C#中可能會非常明顯。 –

0

該代碼看起來不錯。一定要在發佈模式下運行,因爲這可以產生很大的差異。另外,我甚至看到平臺目標設置對某些低級操作有重大影響。因此,請嘗試x86和x64。

我知道了設立在釋放模式運行「任何CPU」與「優化代碼」,並且它在39毫秒運行。

0

社區,非常感謝您的幫助。 問題是:我使用啓用IntelliTrace的VS2010運行它:事件&調用,而不是事件。這是一個簡單的解釋。