Gen*_*ade 13 c# generics collections performance
我注意到迭代了一个原始集合(T [])的性能损失,该集合已被强制转换为通用接口集合(IList或IEnumberable).
例如:
private static int Sum(int[] array)
{
int sum = 0;
foreach (int i in array)
sum += i;
return sum;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码执行速度明显快于下面的代码,其中参数更改为类型IList(或IEnumerable):
private static int Sum(IList<int> array)
{
int sum = 0;
foreach (int i in array)
sum += i;
return sum;
}
Run Code Online (Sandbox Code Playgroud)
如果传递的对象是原始数组,并且如果我尝试将循环更改为for循环而不是foreach循环,则仍会出现性能损失.
我可以通过编码来解决性能问题:
private static int Sum(IList<int> array)
{
int sum = 0;
if( array is int[] )
foreach (int i in (int[])array)
sum += i;
else
foreach (int i in array)
sum += i;
return sum;
}
Run Code Online (Sandbox Code Playgroud)
有没有更优雅的方法来解决这个问题?感谢您的时间.
编辑:我的基准代码:
static void Main(string[] args)
{
int[] values = Enumerable.Range(0, 10000000).ToArray<int>();
Stopwatch sw = new Stopwatch();
sw.Start();
Sum(values);
//Sum((IList<int>)values);
sw.Stop();
Console.WriteLine("Elasped: {0} ms", sw.ElapsedMilliseconds);
Console.Read();
}
Run Code Online (Sandbox Code Playgroud)
Mag*_*tLU 19
如果此方法对性能至关重要,那么最好的选择是Sum使用int[]as作为参数创建重载.CLR的JIT可以检测数组上的foreach样式迭代,并且可以跳过范围检查并直接寻址每个元素.循环的每次迭代在x86上需要3-5条指令,只有一次内存查找.
使用IList时,JIT不了解底层集合的结构并最终使用IEnumerator<int>.循环的每次迭代使用两个接口调用 - 一个用于Current,一个用于MoveNext(2-3个内存查找和每个调用).这最有可能导致约20个非常昂贵的指令,你可以做的很少.
编辑:如果您对未附带调试器的发布版本中JIT发出的实际机器代码感到好奇,请点击此处.
int s = 0;
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 xor esi,esi
foreach (int i in arg)
00000007 xor edx,edx
00000009 mov edi,dword ptr [ecx+4]
0000000c test edi,edi
0000000e jle 0000001B
00000010 mov eax,dword ptr [ecx+edx*4+8]
s += i;
00000014 add esi,eax
00000016 inc edx
foreach (int i in arg)
00000017 cmp edi,edx
00000019 jg 00000010
Run Code Online (Sandbox Code Playgroud)
int s = 0;
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,1Ch
00000009 mov esi,ecx
0000000b lea edi,[ebp-28h]
0000000e mov ecx,6
00000013 xor eax,eax
00000015 rep stos dword ptr es:[edi]
00000017 mov ecx,esi
00000019 xor eax,eax
0000001b mov dword ptr [ebp-18h],eax
0000001e xor edx,edx
00000020 mov dword ptr [ebp-24h],edx
foreach (int i in arg)
00000023 call dword ptr ds:[009E0010h]
00000029 mov dword ptr [ebp-28h],eax
0000002c mov ecx,dword ptr [ebp-28h]
0000002f call dword ptr ds:[009E0090h]
00000035 test eax,eax
00000037 je 00000052
00000039 mov ecx,dword ptr [ebp-28h]
0000003c call dword ptr ds:[009E0110h]
s += i;
00000042 add dword ptr [ebp-24h],eax
foreach (int i in arg)
00000045 mov ecx,dword ptr [ebp-28h]
00000048 call dword ptr ds:[009E0090h]
0000004e test eax,eax
00000050 jne 00000039
00000052 mov dword ptr [ebp-1Ch],0
00000059 mov dword ptr [ebp-18h],0FCh
00000060 push 0F403BCh
00000065 jmp 00000067
00000067 cmp dword ptr [ebp-28h],0
0000006b je 00000076
0000006d mov ecx,dword ptr [ebp-28h]
00000070 call dword ptr ds:[009E0190h]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
592 次 |
| 最近记录: |