如何验证函数是否已在C#中缓存?

时间:2011-03-20 23:20:10

标签: c# .net compiler-construction clr jit

我在C#中创建了以下函数:

float GetPI()
{
  return 22.0f/7.0f;
}

void Calculate()
{
  float f1 = GetPI()*4;
  float f2 = GetPI()*5;
}

如果我创建了一个发布版本,我将如何验证JIT编译器是否将缓存22/7计算,或者每次调用函数GetPI时是否会计算它?

PS:我没有视觉C#studio专业版

编辑:将22/7更改为22.0f / 7.0f以使示例函数更准确

3 个答案:

答案 0 :(得分:4)

我不确定缓存是什么意思。除非编译器不进行任何常量折叠(在这种情况下它将执行)或运行时没有内联函数(在这种情况下可能会内联),否则它不会自动为您执行任何“缓存”。 / p>


表达式22f/7f是一个常量表达式,可以在编译时计算(aka,constant folding)。因此在编译的程序集中,它将显示为:

float GetPI()
{
  return 3.142857f; // however many digits of precision
}

如果有机会,编译器将始终进行这种优化。除非有一个编译器选项来禁用它(我不确定有)。要验证这种情况,您可以使用Reflector(正如其他人指出的那样)来查看已编译的程序集。您应该看到它确实是这样做的,无论是Debug或Release版本还是使用快速版本(除非明确禁用此优化)。


如果函数足够简单,运行时可能会内联函数调用。因此,它不会调用此函数,而是将结果插入到函数调用的位置。看到这只是一个只返回一些数字的函数,它可能会做这个优化。我不知道是否有办法在没有通过调试器实际看到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

答案 1 :(得分:1)

下载并安装.NET Reflector(最初由Lutz Roeder编写,现在由Red Gate维护)。如果您不想付款,可能需要查找旧版本。

当您在Reflector中打开代码时,您可以看到编译器所做的更改。

这不会向您展示JIT优化,您需要在调试器中逐步执行机器代码,但我很确定这种情况将由C#编译器进行评估。

答案 2 :(得分:1)

有很多方法。一个方便的是使用.NET Reflector。

在Reflector中打开装配,选择C#,在树视图中找到方法,选择工具/反汇编。反汇编程序将显示如下内容:

public float GetPI()
{
    return 3f;
}