【问题标题】:Actual Performance of Fields vs. Properties字段的实际性能与属性
【发布时间】:2010-12-06 17:52:23
【问题描述】:

我正在做一些构建后的 CIL 编织,将 CIL 添加到程序集中的所有方法(换句话说,大量方法)。每个方法都会检查特定值是否为空。示例(C# Reflector 版本的 CIL 代码):

// CIL woven region start
if (MyType.Something == null) {
 // ... some new stuff
}
// CIL woven region end

将 MyType.Something 作为属性与字段对性能有何影响?我知道我已经读过 C# 编译器执行特殊优化,在这种情况下应该没有性能影响......但是在直接 CIL 代码(没有 C# 编译器)的情况下呢......?或者是允许这些优化的 JIT 编译器(所以直接 CIL 代码仍然有好处)?

为静态属性的访问器发出 OpCode.Call 的性能是否会比 Ldsfld 差(请记住,由于程序集中的每个方法都是编织的,因此需要数万次调用)?

谢谢。

【问题讨论】:

  • 您能解释一下您为什么决定实施它吗?

标签: c# reflection reflection.emit


【解决方案1】:

在为 SlimDX 开发数学库时,我们发现在 .NET 3.5 SP1 之前的框架上,使用数学类型成员的字段(例如 Vector3 的 X、Y、Z)会带来不成比例的性能提升超过属性。换句话说,对于频繁访问属性的小型数学函数,这种差异很明显。

自 .NET 3.5 SP1 以来,这已得到改进(请参阅 JIT inling)。虽然我相信在此之前的 JIT 仍将内联小方法(属性毕竟只是方法),但早期框架中存在一个错误,阻止内联采用或返回值类型的方法。

请注意,差异仍然很小。除了最关键的性能情况外,我仍然会选择在所有情况下使用属性。

【讨论】:

  • 好的,谢谢。我们使用的是 3.5 SP1。只是好奇,由于代码是 CIL 并且仅在构建后可见,您仍然使用属性的理由是什么?
  • 在您的情况下,我不知道我会使用属性。通常,从库设计和维护的角度来看,属性背后的合理性是稳健性,但这似乎并不适用于此。
  • 我从 ParentChild 属性中删除了我的 Barnes-Hut 四叉树中的 { get; protected set; },并在注意到之后在 .NET 5.0 中的重力模拟器中获得了 25% 的免费性能提升它们出现在 Performance Profiler 的 Self CPU 的 Top Functions 列表中。
【解决方案2】:

C# 编译器不会对此进行优化,不,但据我所知,JIT 编译器通常可以内联琐碎(和非虚拟)属性。

与所有性能问题一样:如有疑问,请进行测试!

【讨论】:

  • 我不确定如何在不遭受“观察者”效应的情况下进行测试,所以我希望有人可以立即知道。
  • @JeffN825:我认为如果您可以在实际代码中应用测试并且无法观察到任何差异,那么这足以证明任何差异都微不足道:)跨度>
【解决方案3】:

在任一方向上的影响都很小。如果你的属性看起来像这样::

public static SomeType PropertyName
{
    get {return MyType.propertyName;}
    set {MyType.propertyName = value;}
}

确实应该有一个非常小的差异。 Jit 编译器应该将 call MyType.set_Property 内联到字段加载中,但即使由于错误而不能。我个人会谨慎行事,并坚持使用属性设置器和获取器,因为方法主体可能会发生变化,因此原始字段访问/突变可能还不够。

如果您想测试,您可以强制您发出的方法使用 MethodImpl 来关闭内联或优化。然后比较差异,我真的怀疑它会很重要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 1970-01-01
    • 2012-02-05
    相关资源
    最近更新 更多