Kel*_*ron 0 c# compiler-construction optimization accessor
我最近发现,对于某些类型的财务计算,以下模式更容易遵循和测试,尤其是在我们可能需要从计算的各个阶段获取数字的情况下.
public class nonsensical_calculator
{
...
double _rate;
int _term;
int _days;
double monthlyRate { get { return _rate / 12; }}
public double days { get { return (1 - i); }}
double ar { get { return (1+ days) /(monthlyRate * days)
double bleh { get { return Math.Pow(ar - days, _term)
public double raar { get { return bleh * ar/2 * ar / days; }}
....
}
Run Code Online (Sandbox Code Playgroud)
显然,这通常导致在给定公式内多次调用相同的访问器.我很好奇编译器是否足够聪明,可以优化掉这些重复的调用而不会有状态的中间变化,或者这种风格是否会导致性能下降.
进一步阅读建议总是受到赞赏
据我所知,C#编译器没有对此进行优化,因为它不能确定副作用(例如,如果你accessCount++在getter中有什么?)看看Eric Lippert的优秀答案
从那个答案:
C#编译器永远不会进行这种优化; 如上所述,这样做将要求编译器对应于被调用的代码,并验证其计算的结果在被调用者代码的生命周期内不会发生变化.C#编译器不这样做.
JIT编译器可能会.没有理由不能.它的所有代码就在那里.内联属性getter是完全自由的,如果抖动确定内联属性getter返回一个可以缓存在寄存器中并重新使用的值,那么它可以自由地执行.(如果您不希望它这样做,因为可以在另一个线程上修改该值,那么您已经遇到了竞争条件错误;在您担心性能之前修复该错误.)
只是一个注释,在C#编译器团队中看到Eric,我相信他的答案:)
一些随意的想法.
首先,正如其他人所指出的那样,C#编译器不会进行这种优化,尽管抖动可以自由地进行.
其次,回答性能问题的最佳方法是尝试并查看.秒表课是你的朋友.两种方式尝试十亿次,看看哪一种更快; 那你就知道了.
第三,当然花时间优化已经足够快的东西是没有意义的.在花费大量时间进行基准测试之前,花一些时间进行分析并寻找热点.这不太可能是一个.
第四,另一个答案建议将中间结果存储在局部变量中.请注意,这样做可以在某些情况下使事情变得更快,而在其他情况下,可以使速度变慢.有时,不必要地重新计算结果比存储它更快,并在需要时再次查找.
怎么可能?具有少量寄存器的芯片架构 - 我正在看着你,x86--要求抖动非常明智地了解哪些本地变为寄存器,哪些是堆栈访问.鼓励抖动将不经常使用的东西放在一个寄存器中有时意味着从该寄存器中强制使用其他东西,这样可以从寄存器中获得比不经常使用的值更多的好处.
简而言之:不要试图从舒适的扶手椅中猜出抖动; 现实世界代码的行为可能会违反直觉.根据实际的经验测量做出绩效决策.