我在 XNA 中四处寻找,发现其中的Vector3
类使用公共字段而不是属性。我尝试了一个快速基准测试,发现struct
差异非常显着(将两个向量加在一起 1 亿次需要 2.0 秒的属性和 1.4 秒的字段)。对于引用类型,差异似乎并没有那么大,但确实存在。
那为什么呢?我知道一个属性被编译成get_X
和set_X
方法,这会产生方法调用开销。但是,这些简单的 getter/setter 不总是被 JIT 内联吗?我知道你不能保证 JIT 决定做什么,但肯定这在概率列表中相当高吗?还有什么可以将公共字段与机器级别的属性分开?
我一直想知道的一件事是:自动实现的属性 ( public int Foo { get; set; }
) 如何比公共字段“更好”的 OO 设计?或者更好地说:这两者有什么不同?我知道通过反射使它成为一个属性更容易,但还有什么?我敢打赌,这两个问题的答案是一样的。
顺便说一句:我正在使用 .NET 3.5 SP1,我认为它解决了带有结构的方法(或结构的方法,我不确定)没有内联的问题,所以不是这样。我想我至少在使用它,它肯定已经安装了,但话又说回来,我使用的是带有 SP1 的 Vista 64 位,它应该有 DX10.1,但我没有 DX10.1 ..
另外:是的,我一直在运行发布版本:)
编辑:我很欣赏快速回答的家伙,但我表示我确实知道属性访问是一个方法调用,但我不知道为什么可能是内联方法比直接字段访问慢。
编辑 2:所以我创建了另一个struct
使用显式 GetX() 方法的方法(我怎么不会错过我的 Java 日子),并且无论我是否禁用内联(通过),它都[MethodImplAttribute(MethodImplOptions.NoInlining)]
执行相同的操作,所以结论:非静态方法显然从不内联,即使在结构上也是如此。
我认为有例外,JIT 可以优化虚拟方法调用。为什么这种情况不会发生在不知道继承的结构上,因此方法调用只能指向一个可能的方法,对吧?还是因为您可以在其上实现接口?
这有点可惜,因为它真的会让我考虑在性能关键的东西上使用属性,但是使用字段让我觉得很脏,我还不如用 C 写我正在做的事情。
编辑 3:我发现这篇帖子是关于完全相同的主题的。他的最终结论是属性调用确实得到了优化。我也可以发誓我已经读过很多次简单的 getter/setter 属性会被内联,尽管callvirt
在 IL 中。那我是不是要疯了?
编辑 4:Reed Copsey 在下面的评论中发布了答案:
回复:Edit3 - 查看我更新的评论:我相信这是 x86 JIT 与 x64 JIT 问题。x64 中的 JIT 并不成熟。随着越来越多的 64 位系统每天上线,我希望 MS 能够迅速改进这一点。——里德·科普西
我对他的回答的回应:
谢谢,这就是答案!我尝试强制 x86 构建,所有方法都同样快,而且比 x64 快得多。实际上,这对我来说非常令人震惊,我不知道我在 64 位操作系统上生活在石器时代。我会在我的回答中包含您的评论,这样它会更好。– 朱利安
谢谢大家!