2012-02-26 39 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代码,发现代码中没有任何区别。因此,对于您的程序,您在测量中观察到的差异本质上似乎是噪音。