Why does the JIT not use the readonly flag for optimization in this case?
我有一个由这个
1 2 3 4 5 6 7 8 | internal class CachePage { internal CachePage(Token[] tokens) { this.tokens = tokens; } private readonly Token[] tokens; // other members don't matter... |
为了简化问题,在类I上有几个
1 2 3 4 | public bool CheckTokens(Token g0, Token g1, Token g2) { return (g2 == tokens[2] && g1 == tokens[1] && g0 == tokens[0]); } |
我向后迭代数组的元素,只进行一次绑定检查。我大概是这么想的。当我查看反汇编的输出时,我实际上看到了每次比较,它实际上都在执行boundcheck。
但是,如果我这样改变方法,多余的边界检查将被消除。
1 2 3 4 5 | public bool CheckTokens(Token g0, Token g1, Token g2) { var t=tokens; return (g2 == t[2] && g1 == t[1] && g0 == t[0]); } |
为什么要增加额外的约束支票?readonly标志是否告诉jit不能对这个私有变量进行赋值?
这是一个低级缓存,因此确定这是否是正确路径花费的时间越少越好。
编辑:这是针对64位.NET 4.5的,使用了ryujit和普通jit。
我在实时交易的世界中工作,在试图从应用程序中榨取最后一点性能的同时,我研究了这个问题。
正如汉斯在问题评论中所说,有些乐观情绪是神经过敏者选择忽视的。其中之一是注册一个方法中多次读取的
简单地说,这是一种权衡,在绝大多数情况下,潜在的好处不值得为抖动付出代价。如果您的性能调优已经达到了微优化的程度,那么显式地启用抖动,通过手动将成员变量提升为局部变量来注册成员变量。这具有连锁效应,使抖动能够执行其他优化,例如消除边界检查。