问题描述
我已经做了一些性能测试,主要是让我可以理解迭代器和简单的for循环的区别。作为其中的一部分,我创建了一个简单的测试集,然后由完全的结果感到惊讶。对于一些方法,64位比32位的快了近10倍。
I've been doing some performance testing, mainly so I can understand the difference between iterators and simple for loops. As part of this I created a simple set of tests and was then totally surprised by the results. For some methods, 64 bit was nearly 10 times faster than 32 bit.
我正在寻找的是为什么这种情况正在发生一些解释。
What I'm looking for is some explanation for why this is happening.
[以下的状态这答案是32位应用程序,由于64位运算。改变多头在32位和64位系统性能良好整数结果。]
[The answer below states this is due to 64 bit arithmetic in a 32 bit app. Changing the longs to ints results in good performance on 32 and 64 bit systems.]
下面是3种方法有问题。
Here are the 3 methods in question.
private static long ForSumArray(long[] array)
{
var result = 0L;
for (var i = 0L; i < array.LongLength; i++)
{
result += array[i];
}
return result;
}
private static long ForSumArray2(long[] array)
{
var length = array.LongLength;
var result = 0L;
for (var i = 0L; i < length; i++)
{
result += array[i];
}
return result;
}
private static long IterSumArray(long[] array)
{
var result = 0L;
foreach (var entry in array)
{
result += entry;
}
return result;
}
我有一个简单的测试工具来测试这种
I have a simple test harness that tests this
var repeat = 10000;
var arrayLength = 100000;
var array = new long[arrayLength];
for (var i = 0; i < arrayLength; i++)
{
array[i] = i;
}
Console.WriteLine("For: {0}", AverageRunTime(repeat, () => ForSumArray(array)));
repeat = 100000;
Console.WriteLine("For2: {0}", AverageRunTime(repeat, () => ForSumArray2(array)));
Console.WriteLine("Iter: {0}", AverageRunTime(repeat, () => IterSumArray(array)));
private static TimeSpan AverageRunTime(int count, Action method)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
for (var i = 0; i < count; i++)
{
method();
}
stopwatch.Stop();
var average = stopwatch.Elapsed.Ticks / count;
return new TimeSpan(average);
}
当我跑这些,我得到如下结果:结果
32位:
When I run these, I get the following results:
32 bit:
For: 00:00:00.0006080
For2: 00:00:00.0005694
Iter: 00:00:00.0001717
64位
For: 00:00:00.0007421
For2: 00:00:00.0000814
Iter: 00:00:00.0000818
我从这个读取的事情是,使用LongLength缓慢。如果我使用array.Length,第一个for循环性能pretty好于64位,而不是32位。
The things I read from this are that using LongLength is slow. If I use array.Length, performance for the first for loop is pretty good in 64 bit, but not 32 bit.
我从这个阅读的另一件事是,遍历数组是作为一个for循环一样高效,而code是更清洁,更易于阅读!
The other thing I read from this is that iterating over an array is as efficient as a for loop, and the code is much cleaner and easier to read!
推荐答案
x64处理器包含,使他们能够在一个单一的指令计算在64位整数运算64位通用寄存器。 32位处理器不具有。因为它的大量使用长
(64位整数)的变量。
x64 processors contain 64 bit general purpose registers with which they can calculate operations on 64 bit integers in a single instruction. 32 bit processors does not have that. This is especially relevant to your program as it's heavily using long
(64-bit integer) variables.
例如,在64集,添加存储在寄存器一对夫妇64位整数,你可以简单地做:
For instance, in x64 assembly, to add a couple 64 bit integers stored in registers, you can simply do:
; adds rbx to rax
add rax, rbx
要在做一个32位x86处理器相同的操作,你必须使用两个寄存器和手动使用第一次手术的进了第二操作:
To do the same operation on a 32 bit x86 processor, you'll have to use two registers and manually use the carry of the first operation in the second operation:
; adds ecx:ebx to edx:eax
add eax, ebx
adc edx, ecx
更多指令和寄存器少意味着更多的时钟周期,内存读取,...这最终会导致性能降低。所不同的是非常显着的数字运算应用程序。
More instructions and less registers mean more clock cycles, memory fetches, ... which will ultimately result in reduced performance. The difference is very notable in number crunching applications.
有关.NET应用程序,它似乎是64位的JIT编译器执行更积极的优化提高整体性能。
For .NET applications, it seems that the 64-bit JIT compiler performs more aggressive optimizations improving overall performance.
关于你提到的有关数组迭代点,C#编译器是足够聪明的识别的foreach
在阵列和特别对待他们。生成的code等同于使用为
循环,它在推荐使用的foreach
如果你不'吨需要改变数组元素中的循环。除此之外,运行时识别模式的for(int i = 0; I&LT;则为a.length; ++ I)
和阵列循环内访问忽略绑定检查。这不会在 LongLength
情况发生,会导致性能下降(无论是32位和64位的情况下);因为你将使用长
变量与 LongLength
,32位性能将得到更加恶化。
Regarding your point about array iteration, the C# compiler is clever enough to recognize foreach
over arrays and treat them specially. The generated code is identical to using a for
loop and it's in recommended that you use foreach
if you don't need to change the array element in the loop. Besides that, the runtime recognizes the pattern for (int i = 0; i < a.Length; ++i)
and omits the bound checks for array accesses inside the loop. This will not happen in the LongLength
case and will result in decreased performance (both for 32 bit and 64 bit case); and since you'll be using long
variables with LongLength
, the 32 bit performance will get degraded even more.
这篇关于这是为什么快64位超过32位?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!