gpt4 book ai didi

c# - 多态性能命中

转载 作者:行者123 更新时间:2023-11-30 22:17:07 25 4
gpt4 key购买 nike

我正在对一些类建模以表示 C# 中的度量单位。例如,我使用 IDistanceUnit 接口(interface)和基 DistanceUnit 类对毫米和英寸进行建模,提供通用的实现细节。

在每个具体类中都有这样定义的基本算术函数:

public class Inches : 
DistanceUnit<Inches>,
IDistanceUnit,
INumericUnit<Inches, IDistanceUnit>
{
// ... snip ...
public Inches Add(IDistanceUnit unit)
{
return new Inches(Value + unit.ToInches().Value);
}
// ... snip ...
}

对转换为英寸和毫米的 10,000,000 次不同值的加法进行基准测试,但可以接受性能下降。手动执行转换的原始 double 大约需要 70-100 毫秒,而类大约需要 700-1000 毫秒。

我可以将细节抽象到 DistanceUnit 基类中并删除一些不必要的重复:

public abstract class DistanceUnit<TConcrete>
IDistanceUnit,
INumericUnit<TConcrete, IDistanceUnit>
where TConcrete :
IDistanceUnit,
INumericUnit<TConcrete, IDistanceUnit>,
new()
{
// ... snip ...
public TConcrete Add(IDistanceUnit unit)
{
TConcrete result = new TConcrete();
reuslt.Value = Value + ToThis(unit).Value();
return result;
}
// ... snip ...
}
// ToThis() calls the correct "ToXYZ()" for the current implementing class

这使我的表现至少又下降了 10 倍。与 800 毫秒相比,我看到大约 8000 毫秒,只是将实现移入基类。

我已经从手动测试中排除了一些事情:

  • 切换到使用 ToThis(IDistanceUnit) 没有明显的变化在具体类而不是直接类中使用时性能下降调用“ToInches”或“ToMillimeters”
  • 使用无参数构造函数(new TConcrete())创建对象并赋值后来的值(value)最差的几毫秒的性能达到超过 10,000,000计算。

我正在使用以下代码对我的结果进行基准测试:

int size = 10000000;
double[] mms = new double[size];
double[] inches = new double[size];

// Fill in some arbitrary test values
for (int i = 0; i < size; i++)
{
mms[i] = i;
inches[i] = i;
}

Benchmark("Manual Conversion", () =>
{
for (int i = 0; i < size; i++)
{
var result = mms[i] + (inches[i] * 25.4);
}
});

Benchmark("Unit Classes", () =>
{
for (int i = 0; i < size; i++)
{
var result = (new Millimeters(mms[i])) + (new Inches(inches[i]));
}
}

Benchmark 只是围绕提供的 Action 调用秒表,并打印出耗时(以毫秒为单位)。

唯一似乎造成主要差异的是 Add 函数从具体类移动到抽象基类,但我不明白为什么我会有一个几乎10 倍的性能下降。 谁能给我解释一下(如果可能的话,建议一种无需代码重复即可获得更快速度的方法)?

最佳答案

对于我在评论中所说的第一个性能命中,我需要了解一些实现细节:ToInches() 方法、ToThis() 方法、Value 属性的类型或代码。

对于第二次性能命中,最可能的原因是您对基类使用了 new() 约束并使用了
TConcrete result = new TConcrete();

编译器生成 Activator.CreateInstance<TConcrete>()在这种情况下,此方法在引擎盖下使用反射并且速度很慢。如果你有数百万个实例化,它肯定会降低性能。 Here您可以从 Jon Skeet 那里找到一些基准。

如果您使用 >= 3.5 框架,您可以使用表达式树来构建基类中对象的快速通用实例化:

private static Func<TConcrete> _createFunc;

private static TConcrete CreateNew()
{
if (_func == null)
{
_createFunc = Expression.Lambda<Func<TConcrete>>(Expression.New(typeof (TConcrete))).Compile();
}
return _createFunc.Invoke();
}

public TConcrete Add(IDistanceUnit unit)
{
TConcrete result = CreateNew();
result.Value = Value + ToThis(unit).Value();
return result;
}

关于c# - 多态性能命中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16921053/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com