我并不是真正微观管理应用程序的性能,但我对以下场景感到好奇。
对于Structs,默认情况下,C#编译器生成布局LayoutType。顺序。这意味着字段应保持程序员定义的顺序。我相信这是为了支持与非托管代码的互操作性。但是,大多数用户定义的Structs与互操作性无关。我已经读过,为了获得更好的性能,我们可以明确指定LayoutKind.Auto,让CLR决定最佳布局。为了测试这个,我想到在两种布局上做一个快速的基准测试。但是我的结果表明默认布局(LayoutType.Sequnetial)比显式布局(LayoutType.Auto)快一点。我期待相反的结果。
以下是我在我的机器上运行的测试(运行.NET 4的x86)
//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;
}
}
以下是我在我的机器上运行的示例结果(运行.NET 4的x86)
Struct LayoutKind.Sequence(默认值)0.7488
Struct LayoutKind.Auto(显式)0.7643
我多次运行此测试,并且我总是得到Struct LayoutKind.Sequence(默认值)&lt; Struct LayoutKind.Auto(显式)
即使它是微毫秒的差异,我也期望Struct LayoutKind.Auto(显式)低于Struct LayoutKind.Sequence(默认值)。
有谁知道这个的原因?或者是我的基准测试不够准确,给我正确的结果?
答案 0 :(得分:2)
我已经在我的系统上测试了你的代码,并发现当测试运行很多次时所花费的平均时间是相同的,每次测试运行稍微偏向于一个或另一个替代方案。这适用于调试和发布版本。
另外,作为一个快速检查,我查看了调试器中的x86代码,我发现生成的代码没有任何区别。因此,对于您的程序,您在测量中观察到的差异实际上似乎是噪音。
答案 1 :(得分: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中进一步解释。
答案 2 :(得分:0)
我相信您的字段布局方式没有区别。您声明它们的方式,填充将是相同的。如果您尝试交错不同大小的字段,您应该会看到差异,至少在大小上,如果不是在速度上。
此外,根据 this blog post,具有引用字段的结构被更改为自动布局(这意味着您实际上是在做同样的事情!)。
public struct MyStruct
{
private byte b1;
public long a;
private byte b2;
public long b;
private byte b3;
public long c;
private byte b4;
public long d;
}