调用方法会降低性能吗?
例如:
代码 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 ?
For example :
Code 1:
void Main()
{
Console.WriteLine("Some texts");
}
Code 2:
void Main()
{
Foo();
}
void Foo()
{
Console.WriteLine("Some texts");
}
Does code 2 run slower than code 1 ? I though when we build the release the JIT will inline code 2 so then code 2 will run as fast as code 1. But when I test them with LinqPad I got the IL result :
Code 1:
IL_0000: ldstr "Some texts"
IL_0005: call System.Console.WriteLine
Code 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
As we can see the IL result in code 2 has some extra steps for calling Foo(), does this prove that code 2 run slower than code 1 ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
首先,您查看的是 IL,而不是 JIT 汇编代码。你所展示的并不能证明任何事情。您需要查看 JITted 输出以查看 JITter 是否内联了代码。请注意,JITter 因平台(例如,x86 与 x64)以及框架版本的不同而不同。
其次,当然,书面版本第二版的运行速度比版本一慢。当我说“如所写”时,我的意思是假设 JITter 尚未内联版本二中的调用。额外的调用添加了一些机器指令,这当然需要一些额外的周期来执行(再次,不要忘记我说“如所写!”)。然而,性能上的差异极不可能是有意义的。您必须在最紧密的循环中执行数万亿次迭代才能看到有意义的性能差异。
First off, you're looking at the IL, not the JITted assembly code. What you have shown doesn't prove anything. You need to look at the JITted output to see if the JITter inlined the code or not. Note that the JITter differes from platform to platform (x86 vs. x64, for example) and version of the Framework to version of the Framework.
Secondly, of course as written version two will run slower than version one. When I say "as written" I mean that this assumes that the JITter hasn't inlined the call in version two. The extra call adds a few machine instructions which of course take a few extra cycles to execute (again, don't forget I said "as written!"). However the difference in performance is highly extremely magnificently unlikely to be meaningful. You would have to be doing this in the tightest of loops for trillions and trillions of iterations to ever see a meaningful performance difference.
是的,如果方法调用没有被 c# 编译器或 jit 编译器内联,那么它们会稍微减慢代码执行速度。但是,除非您的代码在循环中运行并执行一百万次左右,否则您应该真正专注于生成干净、可理解和可维护的代码。当我开始编程时,单个语句的执行时间以毫秒或微秒为单位。如今,它们以纳秒为单位进行测量。时间通常主要浪费在I/O操作上。有时也可以归咎于糟糕的算法。如果您的设计结构清晰,那么与从一开始就进行时间优化并因此可能结构不良的代码相比,用更好的代码部分替换性能较差的代码部分会容易得多。
我最近经历过。我必须在 Visio 中的 ac# 程序中生成复杂的图形。事实证明,Visio 自动化非常慢。创建图形花了几分钟。幸运的是,我已将所有图形内容放在一个组件中,该组件通过产品中立的界面公开图形命令。即:界面不包含任何 Visio 特定的内容。用新的 SVG 组件替换我的 Visio 组件非常容易,它在不到一秒的时间内完成了相同的任务。此外,我的算法或程序的任何其他部分绝对不需要进行任何更改。
当然,我的图形包装器组件添加了更多方法调用。此外,它是通过接口访问的,这进一步减慢了整个过程。然而,最终,正是这个接口和这些额外的方法调用,使我能够实现更快的解决方案。请记住:分钟与不到一秒!
Yes method calls slow down the code execution a tiny little bit, if they a not inlined by the c#-compiler or the jit-compiler. However, unless your code runs in a loop and is executed a million times or so, you should really focus on producing clean, understandable and maintainable code. When I started with programming the execution times for single statements where measured in milli- or microseconds. Today they are measured in nanoseconds. Time usually is mainly wasted for I/O operations. Bad algorithms can also be blamed some times. If your design is cleanly structured, it will be much easier to replace a poorly performing code-part by a better one, compared to a code that was time-optimized from the beginning and therefore probably badly structured.
I experienced that recently. I had to produce a complicated graphic in Visio in a c# program. It turned out that Visio-automation was very slow. It took minutes to create the graphic. Fortunately, I had put all the graphics stuff in a component, which exposed graphics commands through a product neutral interface. I.e.: the interface did not contain any Visio specific stuff. It was very easy to replace my Visio component by a new SVG component, which did the same task in less than a second. In addition, absolutely no changes had to be made in my algorithms or in any other part of my program.
Of cause, my graphics wrapper component adds more method calls. In addition, it is accessed via an interface, which slows down the whole thing even more. However, in the end, it was this interface and these extra method calls, which allowed me to implement a much faster solution. Remember: minutes versus less than one second!
在这种情况下,由于这是我上次阅读此类内容的实现,是的,它将被内联。
一般来说,答案是可能的——关于内联规则的文档是信息性材料,主要是在博客中,而不是规范性文档。不仅版本之间的细节可能会发生变化,而且几乎肯定会发生变化。
实践中:
如果您怀疑性能热点可以从手动内联中受益,请尝试并再次进行分析。或者至少看看该特定片段的即时代码。
理论上:
尽管如此,我还是喜欢知道小方法是内联的。
In this case, with the implementation as it was the last time I read on such things, yes it will be inlined.
In general, the answer is maybe - what documentation is out there on the rules for inlining is informative material, mostly in blogs, rather than normative documentation. Not only could the details change between versions, they almost certainly will.
In practice:
If you suspect that a performance hot-spot could benefit from manual inlining, then try it and profile again. Or at least look at the jitted code for that particular piece.
In theory:
Still, I like knowing that small methods are inlined, all the same.
它是如此微不足道(阅读:可能有),你不需要担心它。
Its so trivial (read: there might be), you shouldn't need to worry about it.
C# 编译器不进行内联,这就是您在 IL 代码中看到的内容。内联是 JIT 优化器的工作,它在运行时执行(如果它决定内联函数会使程序更高效)。
The C# compiler does not do inlining, and this is what you see in the IL code. Inlining is the job of the JIT optimizer, which does it during runtime (if it decides inlining a function makes the program more efficient).
编译器创建自己的代码解释(汇编代码),因此代码示例将以相同的方式为 CPU 进行处理。 (在释放模式下)
The compiler creates his own interpretation of the code (assembly code), so the code examples will be processed in the same thing for the CPU. (in release mode)
方法调用有一些开销,例如创建新的方法框架。执行此操作将需要额外的 CPU 周期。如果您正在进行系统编程,例如开发驱动程序,这是一个很好的问题,但没有真正被问到。代码的可读性也很重要。
如果您编写非系统应用程序,那么考虑方法调用的时间没有多大意义。在非系统应用程序中,可读性、可维护性和灵活性非常重要。
如果你看一下 java 运行时库的源代码,比如 Java 8,我认为作者并没有过多考虑执行方法所需的时间。在 java 运行时库中,使用了大量的帮助方法。
A method call has overheads such as creating a new method frame. It will additional CPU cycles to do this. If your are doing systems programming, such as developing a driver, its a good question to ask but not really asked. Code readbility is also importtant.
If your writing non-systems application then factoring in the time for method call does not make much sense. In non-systems application readability, maintanability and flexibility are really important.
If you take a look at the source code for the java runtime library, lets say Java 8, I do not think the authors thought much about the time it takes to execute methods. In the java runtime library there are loads of help methods that are used.