与返回值的方法相比,void方法最基本的更快/更少的开销吗?

时间:2012-08-30 15:43:46

标签: c# .net cil il

我无法在SO或互联网上找到类似的问题/答案,而且这个问题也没用,这可能是我在MSIL上阅读时遇到的一个问题。我非常想知道在我的场景中IL操作执行是如何工作的,即使这不是一个我没有其他人要问的实际问题。

前提:

请记住,MSIL命令和函数的执行分三步完成:

  1. 将命令操作数或函数参数压入堆栈。
  2. 执行MSIL命令或调用功能。命令或函数从堆栈中弹出它们的操作数(参数)并推送到堆栈结果(返回值)。
  3. 从堆栈中读取结果。
  4. 步骤1和3是可选的。例如,void函数不会将返回值推送到堆栈。

    我知道这是一种方法可以决定需要多少“处理能力”,但为了我的好奇心,我们可以考虑这两种非常基本的方法:

    第一种方法:

    void Method1()
    {
      var result = 1+1;
    }
    

    第二种方法:

    int Method2()
    {
      var result = 1+1;
      return result;
    }
    

    问题:

    因为void方法没有推送返回值(或者是否存在隐式返回)这是否意味着在执行时需要较少的开销而不是第二种方法?

2 个答案:

答案 0 :(得分:6)

但请记住,MSIL不会被执行甚至解释。 MSIL是已编译代码的表达式,因为它将在虚拟机上执行。但是JIT编译器将MSIL转换为机器代码(x86等)。 x86与基于堆栈的虚拟机根本不同。

在最基本的级别,函数返回寄存器中的值。假设寄存器足够大。让我们坚持使用64位值(引用,长整数,双精度和较小值类型)。这些可以在RAX寄存器中返回。在您的简单示例中,两个函数的生成机器代码没有区别。也就是说,Method1将是:

mov rax, 1
inc rax
ret

(并且,是的,我知道智能编译器会将1+1折叠为2。让我们假设那里有内存访问,好吗?)

Method2将是相同的,因为要返回的值已经在RAX寄存器中。

因此,当您使用64位或更小的数量时,返回值的方法与不返回值的方法之间的差异通常会有所不同,如果有的话,只会在它所需的任何指令中将返回值加载到适当的寄存器中。这通常是单mov条指令。这将取决于事情的完成顺序,以及编译器和JITer如何优化事物。

答案 1 :(得分:3)

所有事情都是平等的,做某事比做某事慢。

但请注意,第一种方法的实现将转变为:

void Method1()
{
}

内联之后,甚至没有调用它(如果这是另一个对象的实例方法,那么调用可能被读取字段替换,因为优化不能阻止{{1如果它是null,那么它应该抛出。如果它是静态的,从同一个对象调用,或者编译器确定该对象不能为null,那么甚至不是。零代码。

同时,第二种方法将转变为:

NullReferenceException()

内联后,使用该值的调用将从例如:

转为
int Method2()
{
  return 2;
}

要:

x = Method2();

如果没有使用该值,那么即使没有;它与第一个完全一样。

这种事情正在发生意味着即使在没有内联呼叫的情况下,诸如是否返回某些内容之类的微小差异将大部分丢失,因为即使对更大的因素没有噪声也会丢失,并且也可能发生反...直观地(通过影响是否以某种模糊的方式采用某些优化路径)。示例:生成值,通过将其放入寄存器中“返回”,但也许它在计算时仍然存在,也许它的下一个用途直接在那里工作;因此“返回”它的成本为零。