【问题标题】:Properties slower than fields属性比字段慢
【发布时间】:2023-08-10 07:11:01
【问题描述】:

似乎我遇到的每个帖子都达成了相同的共识:仅返回字段的属性由 JIT 内联,并且与字段具有几乎相同的性能。

但是,我目前的情况似乎并非如此。我的程序进行密集计算,访问许多只是自动获取器和私有设置器的属性。然而,在这种特殊情况下,我只是在复制一个对象。

在启用优化的发布模式下分析代码导致对属性的get 函数的多次调用。对 Copy() 的调用总计高达 ~5.6 毫秒。

但是,当属性转换为字段时,函数的运行速度比使用属性快 6 倍:

与使用字段相比,比较两个属性的相等性似乎会导致更大的性能损失。这是一个类的 IEquatable 实现的基准,使用相同的代码,但将属性与字段交换。

如果 JIT 应该通过内联属性来优化属性,为什么会发生这种情况?我想保留属性,因为它们的访问控制方面非常方便,但如果它们慢得多,我会坚持使用字段。

编辑:似乎受此问题影响的某些(但不是全部)情况正在使用接口中声明的属性。在这些情况下没有使用其他多态性,但在这些情况下,移除接口会使性能差异达到预期水平。

编辑 2: 如上一次编辑所述,似乎部分问题是由于接口虚拟调用造成的。经过更多调查,似乎在 CLR 中运行基准测试可以正确内联属性,但 JetBrains dotTrace 没有,即使选中了“启用内联”。

【问题讨论】:

  • 这是Release还是Debug版本
  • 发布,64 位,Dotnet Core 2.1 优化
  • 我只是在我的本地做一个简单的测试,如下obj.Property = 5;obj.Field = 5; 在调试期间,当我打开 Dissassembly 窗口时,我可以看到两个调用都是相同的。因此,我假设您通过自动属性访问的对象的大小有点大,因此它们不会被内联...内联她的规则有很多,您可以检查其中的一些*.com/questions/4660004/…
  • 如果您多次访问同一个属性var a = obj.PropertyA.Something(); 然后下一行var b = obj.PropertyA.Anotherthing(); 然后下一行var c = obj.PropertyA.OneAnotherthing(); 我建议将PropertyA 放入一个局部变量然后调用方法等var localProp = obj.PropertyA跨度>
  • 在消费代码中你是进行接口调用还是直接调用?如果接口调用见Performance of “direct” virtual call vs. interface call in C#

标签: c# properties field jit


【解决方案1】:

不幸的是,除了尝试使用

帮助 JITTER 之外,您能做的不多
[MethodImpl(MethodImplOptions.AggressiveInlining)]

AggressiveInlining 如果可能,该方法应该被内联。

现在从技术上讲,这只能用于方法或构造函数,但是您似乎可以在 getter 上测试它并自行设置它们。即它编译(虽然我还没有测试过)

public int someType
{
   [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
   get;
   [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
   set;
}

注意 : in-lining 是一个神奇的黑匣子,抖动的感觉可能喜欢也可能不喜欢,甚至属性也只是一个建议。另请注意,位数也可能会影响它内联的内容。

最后,我认为你的做法是正确的,你应该只使用一个 bechmarker 或 profiler,并相应地进行微优化,

【讨论】:

  • 嗯,即使像这样手动建议内联似乎也对性能没有任何帮助。有趣的是,似乎(在某些情况下,但不是所有情况下)罪魁祸首是属性是在类继承的接口中声明的。没有抽象继承,只是实现接口。我猜 JIT 没有优化这些?
  • @Haus 至于接口,是的,可能还有更多事情要做。我猜您将不得不根据您的性能结果进行字段和直观的优化。我不确定在某些情况下是否有办法强制抖动内联
最近更新 更多