JIT 编译器是否优化(内联)不必要的变量声明?
我读过几篇文章和问题/答案,得出的结论是最佳实践是让 JIT 编译器对内联函数调用进行所有优化。有道理。
内联变量声明怎么样?编译器也会优化这些吗?
也就是说,会不会:
Dim h = (a + b + c) / 2 'Half-Perimeter
If maxEdgeLength / (Math.Sqrt(h * (h - a) * (h - b) * (h - c)) / h) <= MaximumTriangleAspectRatio Then
'Do stuff here.
End If
比这个有更好的性能:
Dim perimeter = a + b + c 'Perimeter
Dim h = perimeter / 2 'Half-Perimeter
Dim area = Math.Sqrt(h * (h - a) * (h - b) * (h - c)) 'Heron's forumula.
Dim inradius = area / h
Dim aspectRatio = maxEdgeLength / inradius
If aspectRatio <= MaximumTriangleAspectRatio Then
'Do stuff here.
End If
当然我更喜欢后者,因为它更容易阅读和调试,但如果它存在的话,我无法承受性能下降。
注意:我已经将此代码确定为瓶颈——无需反驳过早优化。 :-)
I've read several articles and questions/answers that conclude the best practice is to let the JIT compiler do all the optimization for inline function calls. Makes sense.
What about inline variable declarations? Does the compiler optimize these as well?
That is, will this:
Dim h = (a + b + c) / 2 'Half-Perimeter
If maxEdgeLength / (Math.Sqrt(h * (h - a) * (h - b) * (h - c)) / h) <= MaximumTriangleAspectRatio Then
'Do stuff here.
End If
Have better performance than this:
Dim perimeter = a + b + c 'Perimeter
Dim h = perimeter / 2 'Half-Perimeter
Dim area = Math.Sqrt(h * (h - a) * (h - b) * (h - c)) 'Heron's forumula.
Dim inradius = area / h
Dim aspectRatio = maxEdgeLength / inradius
If aspectRatio <= MaximumTriangleAspectRatio Then
'Do stuff here.
End If
Of course I prefer the latter because it's easier to read and debug, but I can't afford the performance degradation if it exists.
Note: I have already identified this code as a bottleneck -- No need for retorts about premature optimization. :-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
临时变量有没有名字都不是问题。
但你可以显着优化这种不平等。
您的代码是:
将两边乘以平方根,消除除法(保留不等式,因为平方根不能返回负数):
现在,将两边平方以消除昂贵的平方根:
取消,并乘以
h
。这样会快很多。如果重复此计算,请考虑缓存此表达式的部分结果以获得更多改进。
使用注释来解释公式。摆脱瓶颈函数中的 Math.Sqrt 调用值得以不太简单的格式编写表达式。
Temporary variables having names or not is a non-issue.
But you can optimize that inequality significantly.
Your code was:
Multiply both sides by the square root, eliminating division (inequality is preserved, because square root cannot return a negative number):
Now, square both sides to eliminate that expensive square root:
Cancel, and multiply by
h
.This will be a lot faster. If this calculation is repeated, consider caching the results of part of this expression for even more improvement.
Use comments to explain the formula. Getting rid of a
Math.Sqrt
call in a bottleneck function is worth writing the expression in a less-than-simple format.顺便说一句,只是为了唱反调,我也想指出这一点:
整个函数的 JIT 内联着眼于 MSIL 的长度(以字节为单位),而不是计算的复杂性。添加局部变量(并期望 JIT 注册它们)可能会增加函数的 MSIL 大小,足以使整个函数不适合内联。
这不太可能像不必要地使用 Math.Sqrt 那样产生那么大的影响,但这是有可能的。正如埃里克·利珀特(Eric Lippert)所说,通过实际测量你会了解更多。然而,这种测量仅对程序的一次特定运行有效,并且不能推广到经常调整 JIT 行为的不同处理器或 .NET 运行时的未来版本(包括服务包)。因此,您需要一种结合分析和经验的优化方法。
By the way, just to play devil's advocate, also I wanted to point this out:
JIT inlining of the entire function looks at the length, in bytes of MSIL, and not the complexity of the calculation. Adding local variables (and expecting the JIT to enregister them) might increase the MSIL size of the function enough to make the whole function not a candidate for inlining.
This isn't likely to make as big a difference as unnecessary use of
Math.Sqrt
, but it is a possibility. As Eric Lippert said, you'll know more by actually measuring. However, such a measurement is only valid for one particular run of the program, and does not generalize to different processors or future versions of the .NET runtime (including service packs) that often tweak JIT behavior. So you want a combined analytical and empirical approach to optimization.