为什么公共领域比属性更快?

我在XNA中玩弄,看到Vector3类使用公共字段而不是属性。 我尝试了一个快速的基准,发现对于一个struct的差异是相当戏剧性的(将两个向量加在一起,一亿次带有属性的2.0s和带有字段的1.4s)。 对于一个参考types,差异似乎并不大,但它在那里。

那么为什么呢? 我知道一个属性被编译成get_Xset_X方法,这会招致方法调用的开销。 但是,这些简单的getter / setter是不是总是被JIT内联? 我知道你不能保证JIT决定做什么,但是肯定这个概率是相当高的? 还有什么是在机器层面上将公共领域与财产分开的?

还有一件事我一直在想:一个自动实现的属性( public int Foo { get; set; } )如何比公共领域更好的OOdevise? 或者更好地说:这两个不同呢? 我知道,使它成为一个财产更容易与反思,但别的? 我敢打赌,这两个问题的答案是一样的。

顺便说一句:我正在使用的.NET 3.5 SP1,我相信固定的问题结构的方法(或结构的方法,我不知道)没有内衬,所以不是这样。 我想我至less使用它,这是肯定安装,但是,然后再次,我使用Vista的64位与SP1应该有DX10.1,除了我没有DX10.1 ..

另外:是的,我一直在运行发布版本:)

编辑 :我很欣赏快速答案的家伙,但我表示,我知道一个属性访问是一个方法调用,但我不知道为什么,可能是内联方法比直接字段访问速度慢。

编辑2 :所以我创build了另一个使用显式GetX()方法的结构(o我怎么不会错过我的Java日子),并执行相同的是否我禁用内联(通过[MethodImplAttribute(MethodImplOptions.NoInlining)] )或不,所以结论:非静态方法显然不是内联的,甚至不在结构上。

我认为有些例外,JIT可以优化虚拟方法。 为什么不能在不知道inheritance的结构上发生,因此方法调用只能指向一种可能的方法,对吗? 或者是因为你可以实现一个接口吗?

这真是一种耻辱,因为它真的会让我思考如何在性能关键的东西上使用属性,但是使用字段会让我感到肮脏,所以我不妨写下我在C中所做的事情。

编辑3 :我发现这个post关于完全相同的主题。 他的最终结论是,财产呼叫确实得到了优化。 我也可以发誓,我已经读了很多次,尽pipe是在IL中的callvirt ,简单的getter / setter属性将被内callvirt 。 那么我疯了吗?

编辑4 :里德·科普塞在下面的评论中发布了答案:

回复:编辑3 – 看到我更新的评论:我相信这是x86 JIT与x64 JIT问题。 在64位的JIT是不成熟的。 我希望随着更多的64位系统每天上网,MS会迅速改进。 – 里德科普塞

我的回答是:

谢谢,这是答案! 我试图强制一个x86版本,所有的方法同样快,比x64快得多。 这实际上对我来说是非常震撼的,我不知道我是在64位操作系统的石器时代生活的。我会在你的回答中包括你的评论,所以它更好。 – JulianR

感谢大家!

编辑2:

我在这里有另一个潜在的想法:

你提到你在x64上运行。 我在x86上testing了这个相同的问题,并且在使用自动属性和字段时看到了相同的性能。 但是,如果您在Connect和邮件列表/论坛post中查看,x64 CLR的JIT是一个不同的代码库,并且与x86 JIT具有非常不同的性能特征。 我的猜测是这是一个地方,其中x64仍然落后。

此外,在.net 3.5sp1中修复的结构/方法/ etc的东西是在x86端,而事实上,调用结构作为参数的方法调用永远不会在.net3.5sp1之前的x86上内联。 这与您的系统上的讨论几乎无关。


编辑3:

另一件事:至于为什么XNA使用字段。 我其实是在游戏节,他们宣布XNA。 Rico Mariani发表了一个演讲,提到了他博客上的许多相同点。 看来XNA的人们在开发一些核心对象时也有类似的想法。 看到:

http://blogs.msdn.com/ricom/archive/2006/09/07/745085.aspx

特别是检查点#2。


至于为什么自动性能比公共领域更好:

它们允许您更改类的第2版中的实现,并根据需要在属性获取/设置例程中添加逻辑,而无需将界面更改为最终用户。 这会对您维护库和代码的能力产生深远的影响。

—-从原来的post – 但发现这不是问题——–

VS 之外运行版本吗? 这可以解释为什么事情没有被优化。 通常,如果您在VS中运行,即使是优化的版本构build,VS主机进程也会禁用JIT的许多function。 这可能会导致性能基准发生变化。

你应该读万斯的这篇文章。 它详细说明为什么方法不总是由JIT'er内联,即使它看起来应该是完全明显的。

http://blogs.msdn.com/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx

XNA必须以XBox 360为目标,.NET Compact Framework中的JIT并不像桌面应用那样复杂。 .NET CF JIT'er不会内联属性方法。

访问一个字段只是一个内存引用,而使用一个属性实际上是调用一个方法,并包含函数调用开销。 使用属性而不是字段的原因是为了使代码免受更改,并为访问提供更好的粒度。 通过不直接暴露你的领域,你可以更好地控制访问是如何完成的。 使用自动字段可以让你获得典型的getter / setter行为,但是可以修改它,而不需要随后将更改传播到代码的其他部分。

例如,假设你想改变你的代码,以便访问一个字段是由当前用户的angular色控制的。 如果你公开了这个字段,你必须触及访问它的代码的每一部分。 通过属性公开它可以让你修改属性代码来添加你的新需求, 但不会导致访问它的任何代码的不必要的改变

  • 公共领域是直接分配
  • 属性是方法,然后是更多的代码,微不足道,但更多。