2012-02-26 107 views
0

我並沒有真正管理應用程序的性能,但我對下面的場景很好奇。C#結構佈局和意外的基準標記結果?

對於Structs,默認情況下,C#編譯器生成佈局LayoutType。順序。這意味着這些字段應該保持程序員定義的順序。我相信這是爲了支持與非託管代碼的互操作性。然而,大多數用戶定義的Struct與互操作性無關。爲了獲得更好的性能,我已經讀過,我們可以明確指定LayoutKind.Auto,並讓CLR決定最佳佈局。爲了測試這個,我想在這兩個佈局上做一個快速的基準測試。但是我的結果表明默認佈局(LayoutType.Sequnetial)比顯式佈局(LayoutType.Auto)快一點。我期待着相反的情況。

下面是我在我的機器上運行(x86上運行.NET 4)

//uses LayoutKind.Sequence by default 
public struct StructSeq 
{ 
    private readonly Byte mb; 
    private readonly Int16 mx; 
    public string a; 
    public string b; 
    public string c; 
    public string d; 
} 

[StructLayout(LayoutKind.Auto)] 
public struct StructAuto 
{ 
    private readonly Byte mb; 
    private readonly Int16 mx; 
    public string a; 
    public string b; 
    public string c; 
    public string d; 
} 

public sealed class Program 
{ 
    public static void Main() 
    { 
     StructSeq sq = new StructSeq(); 
     Stopwatch sw1 = new Stopwatch(); 
     sw1.Start(); 
     for (int i = 0; i < 10000; i++) 
     { 
      sq = ProcessStructSeq(sq); 
     } 
     sw1.Stop(); 
     Console.WriteLine("Struct LayoutKind.Sequence (default) {0}", sw1.Elapsed.TotalMilliseconds); 

     StructAuto so = new StructAuto(); 
     Stopwatch sw2 = new Stopwatch(); 
     sw2.Start(); 
     for (int i = 0; i < 10000; i++) 
     { 
      so = ProcessStructAuto(so); 
     } 
     sw2.Stop(); 
     Console.WriteLine("Struct LayoutKind.Auto (explicit) {0}", sw2.Elapsed.TotalMilliseconds); 
     Console.ReadLine(); 
    } 

    public static StructSeq ProcessStructSeq(StructSeq structSeq) 
    { 
     structSeq.a = "1"; 
     structSeq.b = "2"; 
     structSeq.c = "3"; 
     structSeq.d = "4"; 
     return structSeq; 
    }   

    public static StructAuto ProcessStructAuto(StructAuto structAuto) 
    { 
     structAuto.a = "1"; 
     structAuto.b = "2"; 
     structAuto.c = "3"; 
     structAuto.d = "4"; 
     return structAuto; 
    } 
} 

下面是一個示例的結果我得到我的機器上(x86上運行.NET 4)

測試結構LayoutKind.Sequence(默認值)0.7488

結構LayoutKind.Auto(明確的)0.7643

我跑這個測試多次,我總是得到結構LayoutKind.Sequence(默認)<結構LayoutKind.Auto(明確的)

即使是微毫秒的差異,我很期待結構LayoutKind.Auto(明確)低於Struct LayoutKind.Sequence(默認)。

有誰知道這個的原因?還是我的基準測試不夠準確,給我正確的結果?

回答

0

老實說,它太接近了,除非你正在處理幾百萬個這樣的結構,否則它不會產生任何明顯的差異。實際上,多次運行可能會產生不同的結果。我會調整迭代的次數,並嘗試在沒有附加調試器的情況下運行該程序,以查看是否有任何更改。

只要使用結構體並不會立刻讓你的代碼更快,但是有很多陷阱使得結構比它們的類相當慢。

如果你想優化這個基準,你應該將結構作爲引用傳遞給進程方法,而不是返回另一個結構(避免爲該方法創建2個額外的結構),這應該提供比不同的佈局種:

public static void ProcessStructSeq(ref StructSeq structSeq) 
{ 
    structSeq.a = "1"; 
    structSeq.b = "2"; 
    structSeq.c = "3"; 
    structSeq.d = "4"; 
}   

public static void ProcessStructAuto(ref StructAuto structAuto) 
{ 
    structAuto.a = "1"; 
    structAuto.b = "2"; 
    structAuto.c = "3"; 
    structAuto.d = "4"; 
} 

此外,還有一個點,結構變得比它們的類對應較慢,而這估計根據this MSDN article是在約16字節,並且在this StackOverflow question進一步解釋。

+0

謝謝羅伯特。正如你所建議的,我已經優化了基準,並看到了預期的結果。更改如下:將迭代次數增加到幾百萬,在x86發行版中運行,並將結構作爲參考。 – Spock 2012-02-26 10:04:51

2

我已經在我的系統上測試過您的代碼,並且發現測試運行很多次所需的平均時間是相同的,每次測試都略微偏向一個或另一個替代方案。這適用於調試和發佈版本。另外,作爲一個快速檢查,我查看了調試器中的x86代碼,發現代碼中沒有任何區別。因此,對於您的程序,您在測量中觀察到的差異本質上似乎是噪音。