我在 C# 中创建了以下函数:
float GetPI()
{
return 22.0f/7.0f;
}
void Calculate()
{
float f1 = GetPI()*4;
float f2 = GetPI()*5;
}
如果我创建一个发布版本,我将如何验证 JIT 编译器是否会缓存 22/7 计算,或者是否会在每次调用函数 GetPI 时进行计算?
PS:我没有Visual C# studio专业版
编辑:将 22/7 更改为 22.0f/7.0f 以使示例函数更准确
我不确定你所说的缓存是什么意思。 除非编译器不执行任何常量折叠(在本例中它将执行)或者运行时不会内联您的函数(在本例中可能会执行),否则它不会自动为您执行任何“缓存”。
表达式
22f/7f
是一个常量表达式,可以在编译时求值(又名,常量折叠)。 所以在编译后的程序集中会显示为:
float GetPI()
{
return 3.142857f; // however many digits of precision
}
如果有机会,编译器总是会进行这种优化。 除非有一个编译器选项可以禁用它(我不确定是否有)。 为了验证这种情况是否发生,您可以使用 Reflector(正如其他人指出的那样)来查看编译后的程序集。 您应该看到,无论是调试或发布版本还是使用快速版本,它确实都会这样做(除非明确禁用此优化)。
如果函数足够简单,运行时可能会内联您的函数调用。 因此,它不会调用此函数,而是插入结果来代替函数调用。 由于这只是一个返回一些数字的函数,因此它可能会进行此优化。 我不知道是否有一种方法可以在不通过调试器实际查看 JIT 编译的代码的情况下查看是否会发生这种情况。
如果您的意思是像memoization中那样进行缓存,那么这不会自动完成,您必须自己执行此操作。
如果您想要绝对保证编译器将“缓存”(如不重新计算商)该值,您应该将您的值声明为常量(或使用现有且更准确的
System.Math.PI
常量)。 没有什么是在运行时确定的,一切在编译时都是已知的。 每次您使用此值时,它都会被“内联”,因此您不必担心这一点。
const float PI = 22f / 7f; // will be stored as 3.142857f
// or another way, if you need PI to be a float but want a more accurate value
const float PI = (float)Math.PI; // will store as much precision possible
// note that this only works because Math.PI is declared as a constant
下载并安装.NET Reflector(最初由 Lutz Roeder 编写,现在由 Red Gate 维护)。 如果您不想付费,您可能必须寻找旧版本。这不会向您显示 JIT 优化,您需要在调试器中单步执行机器代码,但我很确定这种情况将由 C# 编译器进行评估。
方法有很多。一种方便的方法是使用 .NET Reflector。
public float GetPI()
{
return 3f;
}