当前位置: 首页 > 编程语言 > C#

C#生成IL for ++运算符 – 何时以及为什么前缀-后缀表示法更快分享

时间:2023-04-10 18:44:04 C#

C#学习教程:C#为++运算符生成IL–什么时候以及为什么Prefix/PostfixNotation更快以及前缀/后缀符号的速度差异,我将非常小心地描述问题,以免EricLippert找到它并激怒我!(关于我为什么要问的更多信息和细节可以在http://www.codeproject.com/KB/cs/FastLessCSharpIteration.aspx?msg=3899456#xx3899456xx/找到)我有四个代码片段如下:-(1)单独,前缀:for(varj=0;j!=jmax;){total+=intArray[j];++j;}(2)单独,后缀:for(varj=0;j!=jmax;){total+=intArray[j];j++;}(3)索引器,后缀:for(varj=0;j!=jmax;){total+=intArray[j++];}(4)索引,前缀:for(varj=-1;j!=last;){total+=intArray[++j];}//last=jmax-1我想做的是证明/反驳此上下文中的前缀和后缀表示法(即局部变量因此不那么可变,不能从另一个线程更改等),如果是的话,为什么会这样。速度测试表明:我因此得出结论,选择前缀表示法比后缀表示法本身没有性能优势。但是,当实际使用运算结果时,这会导致代码比简单丢弃的代码慢。然后我使用Reflector查看生成的IL并发现以下内容:然后我比较了(2)和(3)以找出可以解释速度差异的原因:因此,增加j对于(1)(和(2))IL是://ldloc.0已经在ldloc.0之上的索引器操作中使用过一次ldc.i4.1添加stloc.0(3)看起来像这样:ldloc.0dup//j在堆栈上对于*操作结果*ldc.i4.1添加stloc.0(4)如下所示:ldloc.0ldc.i4.1在堆栈上添加dup//j+1用于*操作结果*stloc。0现在(终于!)问题:(2)是否更快,因为JIT编译器将ldloc.0/ldc.i4.1/add/stloc.0视为简单地将局部变量递增1并将其优化掉?(并且(3)和(4)中dup的存在打破了该模式,因此错过了优化)另外一个补充:如果这是真的,那么至少对于(3),dup不会被另一个替换ldloc.0重新引入那个模式?经过大量研究以确定(我很难过!),我想我已经回答了我自己的问题:答案是可能的。显然,JIT编译器确实会寻找模式(参见http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds-check-elimination-in-the-clr.aspx)来决定何时以及如何优化数组边界检查,但我想我不知道它是否是相同的模式。在这种情况下,这是一个有争议的问题,因为(2)中的相对速度增加是由于更多的事情。事实证明,x64JIT编译器足够聪明,可以确定数组长度是否恒定(并且看起来也是循环中展开次数的倍数):所以代码只是在每次迭代结束时进行边界检查,并且每个展开只是:-total+=intArray[j];j++;000000818B440B10moveax,dwordptr[rbx+rcx+10h]0000008503F0addesi,eax我通过更改应用程序以在命令行上指定数组大小并查看不同的汇编器输出来证明这一点。在此练习中发现的其他内容:-有趣的结果。我会做的是:然后你就会知道抖动是否比其他抖动更好。例如,抖动可能知道在一种情况下它可以删除数组边界检查,但在另一种情况下则不能。我不知道;我不是抖动方面的专家。所有rigamarole的原因是因为在附加调试器时抖动可能会生成不同的代码。如果你想知道它在正常情况下做了什么,那么你必须确保代码是在正常的非调试器环境下搜索的。我喜欢性能测试,我喜欢快速的程序,所以我很欣赏你的问题。我试图重现您的发现但失败了。在我的Inteli7x64系统上的x86|Release配置中的.NET4框架上运行代码示例时,所有四个测试用例产生的时间大致相同。为了进行测试,我创建了一个全新的控制台应用程序项目并使用QueryPerformanceCounterAPI调用来获得一个高分辨率的基于CPU的计时器。我为jmax尝试了两种设置:因为数组的位置通常对性能和循环大小的增加有很大影响。但是,在我的测试中,两种数组大小的行为是相同的。我做了很多性能调整,我了解到的一件事是,您可以非常轻松地优化应用程序以使其在一台特定计算机上运行得更快,同时无意中导致它在另一台运行速度更慢的计算机上运行得更快。我不假设在这里谈论什么。我已经调整了内部循环并花费了数小时和数天的时间来使程序运行得更快,结果却破灭了我的希望,因为我正在我的工作站上优化它并且目标计算机是不同型号的Intel处理器。所以这个故事的寓意是:这就是为什么有些编译器针对不同的处理器有特殊的优化开关,或者针对某些应用程序有不同的版本,即使一个版本可以轻松运行在所有支持的硬盘上所以如果你要做这样的测试,你必须像JIT编译器编写者那样做:你必须在各种硬件上执行测试,然后选择一个组合,这是一种在普遍存在的硬件上提供最低性能的快乐媒介。以上就是C#学习教程的全部内容:C#为++运算符生成IL——什么时候以及为什么前缀/后缀表示法更快。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注——本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: