Tam*_*red 15 c# performance cil
所以我有这两种方法,假设将1000项长整数数组乘以2.第一种方法:
[MethodImpl(MethodImplOptions.NoOptimization)]
Power(int[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
arr[i] = arr[i] + arr[i];
}
}
Run Code Online (Sandbox Code Playgroud)
第二种方法:
[MethodImpl(MethodImplOptions.NoOptimization)]
PowerNoLoop(int[] arr)
{
int i = 0;
arr[i] = arr[i] + arr[i];
i++;
arr[i] = arr[i] + arr[i];
i++;
arr[i] = arr[i] + arr[i];
i++;
............1000 Times........
arr[i] = arr[i] + arr[i];
}
Run Code Online (Sandbox Code Playgroud)
请注意,我仅将此代码用于性能研究,这就是为什么它看起来如此恶心.
令人惊讶的结果是,Power比PowerNoLoop我们检查了IL两者的反编译源并且for循环的内容与每行完全相同的速度快了近50%PowerNoLoop.怎么会这样?
Han*_*ant 12
我的机器上的样品测量,运行测试10次,PowerNoLoop是第一次:
00:00:00.0277138 00:00:00.0001553
00:00:00.0000142 00:00:00.0000057
00:00:00.0000106 00:00:00.0000053
00:00:00.0000084 00:00:00.0000053
00:00:00.0000080 00:00:00.0000053
00:00:00.0000075 00:00:00.0000053
00:00:00.0000080 00:00:00.0000057
00:00:00.0000080 00:00:00.0000053
00:00:00.0000080 00:00:00.0000053
00:00:00.0000075 00:00:00.0000053
Run Code Online (Sandbox Code Playgroud)
是的,慢了约50%.值得注意的是第一次通过测试时的抖动开销,显然它会烧掉更多核心,试图获得编译的巨大方法.请记住,当您不禁用优化程序时,测量会有很大差异,因此无循环版本会慢约800%.
始终寻找解释的第一个地方是生成的机器代码,您可以使用Debug> Windows> Disassembly查看它.主要的麻烦是该PowerNoLoop()方法的序幕.在x86代码中看起来像这样:
067E0048 push ebp ; setup stack frame
067E0049 mov ebp,esp
067E004B push edi ; preserve registers
067E004C push esi
067E004D sub esp,0FA8h ; stack frame size = 4008 bytes
067E0053 mov esi,ecx
067E0055 lea edi,[ebp-0ACCh] ; temp2 variables
067E005B mov ecx,2B1h ; initialize 2756 bytes
067E0060 xor eax,eax ; set them to 0
067E0062 rep stos dword ptr es:[edi]
Run Code Online (Sandbox Code Playgroud)
注意非常大的堆栈大小,4008字节.对于只有一个局部变量的方法来说,它应该只需要8个字节.额外的4000个是临时变量,我将它们命名为temp2.它们被rep stos指令初始化为0 ,需要一段时间.我无法解释2756.
个人添加是非优化代码中的一个非常沉重的事情.我将为您节省机器代码转储并将其写入等效的C#代码中:
if (i >= arr.Length) goto throwOutOfBoundsException
var temp1 = arr[i];
if (i >= arr.Length) goto throwOutOfBoundsException
var temp2 = temp1 + arr[i];
if (i >= arr.Length) goto throwOutOfBoundsException
arr[i] = temp2
Run Code Online (Sandbox Code Playgroud)
一遍又一遍地重复,总共一千次.该temp2变量是麻烦制造者,还有每一个为每个单独的语句.因此向堆栈帧大小添加4000个字节.如果有人在2756猜测,那么我很乐意在评论中听到它.
在方法开始运行之前必须将它们全部设置为0大致是产生50%减速的原因.可能还有一些指令获取和解码开销,它不能轻易地从测量中分离出来.
值得注意的是,当您删除[MethodImpl]属性并允许优化器完成其工作时,它们不会被消除.事实上,该方法根本没有优化,当然因为它不想处理如此大的代码块.
您应该绘制的结论是始终将其留给抖动优化器来为您展开循环.它知道的更好.