在我当前的代码库中,复杂的if
语句通常被委托调用代替。由于代码的结构,同一委托在应用程序过程中将被多次调用。例如,
class ExampleClass
{
private delegate double ExampleDelegate(double x, double y);
private ExampleDelegate _exampleMethod;
private bool _condition1;
...
public double ApiFunction(List<double> a, List<double> b, bool condition2)
{
if ((_condition1 && !condition2) || getCondition3())
{
_exampleMethod = adder;
}
else
{
_exampleMethod = subtracter;
}
double finalResult = 0;
for (int i = 0; i < a.Count; i++)
{
finalResult += _exampleMethod(a[i], b[i]);
}
return finalResult;
}
private double adder(double a, double b)
{
return a + b;
}
private double subtracter(double a, double b)
{
return a - b;
}
}
由于这里的性能是一个问题,所以我想知道JITter是否最终会意识到每次都以内联方式调用这些方法之一,或者以其他方式优化调用。
那么,C#JITter可以内联还是以其他方式优化重复的委托调用?
它不是。委托调用始终是间接调用,并在运行时动态绑定。这是在进行调用时发生的,只有这样才能知道委托对象的值。抖动在此之前运行,优化器无法改善它们,它不知道将要调用什么。
请注意,它假定目标方法是实例方法还是静态方法,因此它不知道目标方法是实例方法还是静态方法。如果重新启动调用堆栈是静态的,则调用存根需要额外的工作。对于x64代码,这些额外的工作更为重要。摘录中值得注意的是,静态方法通常更有意义,因此请当心。
第一次调用是昂贵的,这是在创建调用存根并且需要将目标方法设置为jitt的时候。由于在这种情况下,抖动已经可以正确猜出该方法的外观,因此存根只是一条JMP指令。此后以正常速度运行并且超出JMP的任何调用都不会比正常调用慢得多,尽管您无法像通常使用这些小方法那样受益于内联。.NET没有进行任何更改,因为它不使用解释器,所以它没有像热点编译器那样的东西。
您必须进行测量,请注意,这是非常快速的代码,因此简单的基准测试错误往往会受到损害,并且测量结果将不会非常一致。但是,只有在发现实际性能问题时,才考虑花时间在上面。这并不常见,代表们不要suck。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句