我有一些C#代码执行涉及原始数据类型的一些计算,例如:
public sealed class Calculation
{
private readonly int a, b, c;
public Calculation(int _a, int _b, int _c)
{
this.a = _a; this.b = _b; this.c = _c;
}
public int DoCalculation(int rfactor, int lfactor)
{
return (a / rfactor) + (b / lfactor) + ((a/b)*(rfactor+lfactor));
}
}
如果{a,b,c}是编译时间常数,则可以在CIL级别极大地优化DoCalculation(...)方法中的表达式。我想知道JITer是否将优化DoCalculation(...)方法类似于给定“只读”提示的编译时间常数优化。
您的示例不是一个很好的示例,但是是的,这种优化肯定会发生。在多个层次上,C#编译器首先获得优势。它将使用文字值评估简单表达式并将其替换为结果。也是它在编译时检测溢出的方式。
抖动优化器也这样做,通常是inlining方法的结果。但这对于您的DoCalculation()方法不会发生,它太复杂而无法内联。但是像这样的琐碎:
public static int DoCalculation(int a, int b) {
return a * b;
}
当然可以内联和优化。像Console.WriteLine(Calculation.DoCalculation(4,5))一样生成:
00000003 call 5927D408
00000008 mov ecx,eax
0000000a mov edx,14h // <=== here
0000000f mov eax,dword ptr [ecx]
00000011 mov eax,dword ptr [eax+38h]
00000014 call dword ptr [eax+14h]
请注意如何预先计算结果4 * 5 = 20 = 0x14。
在优化器放弃之前,没有什么确切的规则可以确定何时确切地内联该方法以及表达式可以如何涉及。这可能会有所变化,并且取决于抖动的类型(x86 vs x64 vs ARM)。
如果此代码深入您的关键路径,并且探查器告诉您它负责执行时间的80%以上(请不要跳过探查器!),那么值得您花一些时间来修改该方法看看你得到什么。调试发布模式构建,并确保允许优化器运行。工具+选项,调试,常规,取消选中“抑制模块加载时的JIT优化”选项。
小的更改可能会产生很大的影响,当您通过看似微不足道的编辑使代码速度提高一倍时,感觉会非常不错。还是没有,经过一天的尝试,您一无所获,没有任何保证。但是您肯定会对哪种代码运行良好产生“感觉”,这种体验和见解非常有价值。]