Jon*_*gel 26 .net c# compiler-construction optimization properties
请忽略此问题中的代码可读性.
在性能方面,如下所示代码应如下所示:
int maxResults = criteria.MaxResults;
if (maxResults > 0)
{
while (accounts.Count > maxResults)
accounts.RemoveAt(maxResults);
}
Run Code Online (Sandbox Code Playgroud)
或者像这样:
if (criteria.MaxResults > 0)
{
while (accounts.Count > criteria.MaxResults)
accounts.RemoveAt(criteria.MaxResults);
}
Run Code Online (Sandbox Code Playgroud)
?
编辑:criteria
是一个class
,MaxResults
是一个简单的整数属性(即,public int MaxResults { get { return _maxResults; } }
.
C#编译器是否将其MaxResults
视为黑盒并每次都进行评估?或者它是否足够聪明,可以发现我有3次调用同一个属性而没有在调用之间修改该属性?如果MaxResults
是一块田地怎么办?
优化法则之一是预先计算,所以我本能地像第一个列表那样编写这个代码,但我很好奇是否自动为我做了这种事情(再次忽略代码可读性).
(注意:我对听到'微优化'论证并不感兴趣,这个论点在我发布的特定情况下可能是有效的.我只是想了解正在发生或未发生的一些理论.)
Eri*_*ert 59
首先,实际回答性能问题的唯一方法是实际尝试两种方式并在实际条件下测试结果.
也就是说,其他答案说"编译器"不进行此优化,因为属性可能有副作用是对与错.问题的问题(除了在没有实际尝试和测量结果的情况下根本无法回答的基本问题)是"编译器"实际上是两个编译器:编译为MSIL的C#编译器和JIT编译器,它将IL编译为机器代码.
C#编译器永远不会进行这种优化; 如上所述,这样做将要求编译器对应于被调用的代码,并验证其计算的结果在被调用者代码的生命周期内不会发生变化.C#编译器不这样做.
JIT编译器可能会.没有理由不能.它的所有代码就在那里.内联属性getter是完全自由的,如果抖动确定内联属性getter返回一个可以缓存在寄存器中并重新使用的值,那么它可以自由地执行.(如果您不希望它这样做,因为可以在另一个线程上修改该值,那么您已经遇到了竞争条件错误;在您担心性能之前修复该错误.)
抖动是否真的做内联属性获取之后enregister的价值,我也没办法.我对抖动几乎一无所知.但如果认为合适的话,允许这样做.如果您对是否这样做感到好奇,可以(1)询问团队中编写抖动的人,或者(2)检查调试器中的jitted代码.
最后,让我借此机会注意计算结果一次,存储结果并重新使用它并不总是优化.这是一个非常复杂的问题.有各种优化的东西:
执行时间处理时间
可执行代码大小 - 这对可执行时间有重大影响,因为大代码需要更长时间才能加载,增加工作集大小,对处理器缓存,RAM和页面文件施加压力.在重要的指标(如启动时间和缓存位置)中,小的慢代码通常比快速代码更快.
寄存器分配 - 这也会对执行时间产生重大影响,特别是在x86等具有少量可用寄存器的体系结构中.注册一个值以便快速重用可能意味着可用于需要优化的其他操作的寄存器更少; 或许优化这些操作将取得净胜利.
等等.它变得非常复杂,快速.
简而言之,您不可能知道编写代码来缓存结果而不是重新计算它实际上是(1)更快,或(2)更好的执行.更好的性能并不总是意味着更快地执行特定的例程.更好的性能是确定哪些资源对用户很重要 - 执行时间,内存,工作集,启动时间等等 - 并针对这些事情进行优化.如果没有(1)与客户交谈以了解他们关心的内容,以及(2)实际测量以确定您的更改是否在所需方向上具有可衡量的影响,则无法做到这一点.
如果MaxResults
是属性,那么不,它不会优化它,因为getter可能有复杂的逻辑,比如说:
private int _maxResults;
public int MaxReuslts {
get { return _maxResults++; }
set { _maxResults = value; }
}
Run Code Online (Sandbox Code Playgroud)
如果内联代码,请查看行为会如何变化?
如果没有逻辑...你写的任何一种方法都很好,这是一个非常微小的差异,所有关于它对你(或你的团队)的可读性......你是那个看着它的人.
您的两个代码示例仅保证在单线程环境中具有相同的结果,.Net不是,如果MaxResults
是字段(不是属性).除非您使用同步功能,否则编译器不能假设criteria.MaxResults
在循环过程中不会更改.如果它是一个属性,它不能假设使用该属性没有副作用.
Eric Lippert非常正确地指出,它很大程度上依赖于"编译器"的含义.C# - > IL编译器?还是IL - >机器码(JIT)编译器?并且他指出JIT可能能够优化属性getter是正确的,因为它具有所有信息(而C# - > IL编译器则不一定).它不会改变多线程的情况,但它仍然是一个好点.
每次都会调用并评估它。编译器无法确定方法(或getter)是否是确定性的和纯净的(无副作用)。
请注意,JIT编译器可以内联该属性的实际评估,从而使其与简单字段一样有效。
优良作法是使属性评估成为廉价操作。如果在getter中进行大量计算,请考虑手动缓存结果,或将其更改为方法。
归档时间: |
|
查看次数: |
3265 次 |
最近记录: |