通过接口枚举 - 性能损失 [英] Enumerating via interface - performance loss
问题描述
我有一个小小的争端(这是非常接近的圣战:))与我的同事,有关访问的性能通过的indeces列出的 VS 通过枚举。与一些事实进行操作,我写了下面的测试:
I had a little dispute (which was very close to holy war:) ) with my colleage, about the performance of access to list via indeces VS via enumerator. To operate with some facts, I wrote the following test:
static void Main(string[] args)
{
const int count = 10000000;
var stopwatch = new Stopwatch();
var list = new List<int>(count);
var rnd = new Random();
for (int i = 0; i < count; i++)
{
list.Add( rnd.Next());
}
const int repeat = 20;
double indeces = 0;
double forEach = 0;
for (int iteration = 0; iteration < repeat; iteration++)
{
stopwatch.Restart();
long tmp = 0;
for (int i = 0; i < count; i++)
{
tmp += list[i];
}
indeces += stopwatch.Elapsed.TotalSeconds;
stopwatch.Restart();
foreach (var integer in list)
{
tmp += integer;
}
forEach += stopwatch.Elapsed.TotalSeconds;
}
Console.WriteLine(indeces /repeat);
Console.WriteLine(forEach /repeat);
}
其实,它只是访问的元素。
Actually, it just accesses the elements.
正如我所料,索引访问也较快。这是释放的结果建立在我的机器上:
As I expected, index access was faster. This are the results of Release build on my machine:
0.0347//index access
0.0737//enumerating
不过,我决定改变测了一下:
However, I decided to change test a little:
//the same as before
...
IEnumerable<int> listAsEnumerable = list;
//the same as before
...
foreach (var integer in listAsEnumerable)
{
tmp += integer;
}
...
而现在产量为以下内容:
And now output was following:
0.0321//index access
0.1246//enumerating (2x slower!)
如果我们通过接口枚举相同的列表,性能 2次慢!
If we are enumerating the same list via interface, the performance is 2 times slower!
这个的意思是通过接口2枚举。倍以上列举的实际列表慢
this means "enumerating via interface 2 times slower than enumerating the actual list".
我的猜测是,运行时使用不同的枚举
s:发射名单的在第一测试和一个通用的一个在第二测试。
My guess is that runtime is using different Enumerator
s: the list's in first test and a generic one in the second test.
推荐答案
在使用列表< T>
的的foreach
实际上并不使用的IEnumerable< T>
界面;相反,它使用列表< T> .Enumerator
,这是一个结构
。在琐碎的水平,这意味着略低于间接 - 不必去参考,并使用静态调用,而不是虚拟的电话 - 以及更直接的执行
When using List<T>
, the foreach
doesn't actually use the IEnumerable<T>
interface; rather, it uses List<T>.Enumerator
, which is a struct
. At the trivial level, this means slightly less indirection - not having to de-reference, and using static calls rather than virtual calls - and a more direct implementation.
这些差异是非常非常小,并且在任何合理的真实的例子不同的是噪声。但是,它可能会略微明显,如果测试的只是的的foreach
性能。
These differences are very very small, and in any sensible real-life example the difference is noise. However, it may be marginally noticeable if testing just the foreach
performance.
要进一步来说:的foreach
实际上并不需要的IEnumerable [< T>]
- 它可以工作的纯粹在的GetEnumerator()
/ .MoveNext()
/ .Current
/ .Dispose()
模式; 。这是特别重要的仿制药之前,2.0
To expand on this: foreach
doesn't actually require IEnumerable[<T>]
- it can work purely on the GetEnumerator()
/ .MoveNext()
/ .Current
/ .Dispose()
pattern; this was especially important before generics in 2.0.
不过,这是唯一可能当变量的类型为列表< T>
(其中有一个自定义的的GetEnumerator()
方法)。一旦你有的IEnumerable< T>
,它使用的IEnumerator< T>
However, this is only possible when the variable is typed as List<T>
(which has a custom GetEnumerator()
method). Once you have IEnumerable<T>
, it has to use IEnumerator<T>
这篇关于通过接口枚举 - 性能损失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!