调用方法是否会降低性能

本文关键字:性能 方法 是否 调用 | 更新日期: 2023-09-27 18:17:20

例如:
代码1:

void Main()
{
    Console.WriteLine("Some texts");
}
代码2:

void Main()
{
    Foo();
}
void Foo()
{
    Console.WriteLine("Some texts");
}

代码2比代码1运行得慢吗?我认为,当我们构建发布时,JIT将内联代码2,这样代码2将运行得和代码1一样快。但当我用LinqPad测试它们时,我得到了IL结果:

代码1:

IL_0000:  ldstr       "Some texts"
IL_0005:  call        System.Console.WriteLine
代码2:

IL_0000:  ldarg.0     
IL_0001:  call        UserQuery.Foo
Foo:
IL_0000:  ldstr       "Some texts"
IL_0005:  call        System.Console.WriteLine
IL_000A:  ret      

我们可以看到代码2中的IL结果有一些额外的步骤来调用Foo(),这是否证明代码2比代码1运行得慢呢?

调用方法是否会降低性能

首先,您正在查看IL,而不是编译的汇编代码。你所展示的并不能证明什么。您需要查看JITter的输出,看看JITter是否内联了代码。请注意,不同的平台(例如x86 vs. x64)和不同的框架版本之间的抖动是不同的。

其次,版本2当然会比版本1运行得慢。当我说"如所写"时,我的意思是假设JITter在版本2中没有内联调用。额外的调用增加了一些机器指令,当然需要一些额外的周期来执行(再一次,不要忘记我说的"如所写!")。然而,性能上的差异非常非常大,不太可能有意义。您必须在最紧密的循环中进行数万亿次迭代,才能看到有意义的性能差异。

Yes方法调用如果没有被c#编译器或jit编译器内联,会减慢代码的执行速度。然而,除非您的代码在循环中运行并且执行了一百万次左右,否则您应该真正专注于生成干净、可理解和可维护的代码。当我开始编程时,单个语句的执行时间以毫秒或微秒为单位。如今,它们的测量单位是纳秒。时间通常主要浪费在I/O操作上。糟糕的算法有时也会受到指责。如果您的设计结构清晰,那么与从一开始就对时间进行优化,因此可能结构糟糕的代码相比,用更好的代码替换性能较差的代码部分要容易得多。

我最近经历过。我必须用c#程序在Visio中生成一个复杂的图形。结果显示,视觉自动化非常缓慢。制作这个图形花了几分钟。幸运的是,我把所有的图形内容放在了一个组件中,这个组件通过一个与产品无关的界面公开了图形命令。也就是说:这个界面不包含任何Visio特定的东西。用一个新的SVG组件替换我的Visio组件非常容易,它在不到一秒钟的时间内完成了相同的任务。此外,我的算法或程序的任何其他部分绝对不需要做任何更改。

当然,我的图形包装组件增加了更多的方法调用。此外,它是通过接口访问的,这使整个过程变得更加缓慢。然而,最终,正是这个接口和这些额外的方法调用,使我能够实现更快的解决方案。记住:几分钟vs不到一秒!

在这种情况下,由于它是我最后一次读到这类事情的实现,是的,它将被内联。

一般来说,答案是可能的——关于内联规则的文档是信息材料,主要在博客中,而不是规范文档。这些细节不仅会在不同版本之间发生变化,而且几乎肯定会发生变化。

在实践:

如果您怀疑性能热点可以从手动内联中获益,那么请尝试它并再次进行分析。或者至少看看那个特定部分的编译代码。

在理论:

尽管如此,我还是喜欢知道小方法是内联的。

这是微不足道的(阅读:可能有),你不需要担心它。

c#编译器不进行内联,这就是您在IL代码中看到的。内联是JIT优化器的工作,它在运行时进行(如果它认为内联函数使程序更有效)。

编译器创建他自己的代码解释(汇编代码),因此代码示例将以相同的方式处理CPU。(发布模式)

方法调用有一些开销,比如创建一个新的方法框架。这需要额外的CPU周期。如果你正在做系统编程,比如开发一个驱动程序,这是一个很好的问题,但很少有人问。代码的可读性也很重要。

如果您编写的是非系统应用程序,那么考虑方法调用的时间是没有多大意义的。在非系统应用程序中,可读性、可维护性和灵活性非常重要。

如果你看一下java运行库的源代码,比如java 8,我认为作者并没有考虑到执行方法所花费的时间。在java运行时库中有大量使用的帮助方法。