通过接口枚举 - 性能损失 [英] Enumerating via interface - performance loss

查看:172
本文介绍了通过接口枚举 - 性能损失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小小的争端(这是非常接近的圣战:))与我的同事,有关访问的性能通过的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 Enumerators: 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆