关于IOrderedEnumerable的性能问题 [英] Performance question on IOrderedEnumerable

查看:152
本文介绍了关于IOrderedEnumerable的性能问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是偶然发现 IOrderedEnumerable.Contains [

I just stumbled upon an oddity in IOrderedEnumerable.Contains[^] and was wondering if more people here had the problem or if it is just me...

Consider the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> list = new List<int>();
            for (int i = 0; i < 1000000; i++)
            {
                list.Add(i);
            }
            
            IOrderedEnumerable<int> orderedList = list.OrderBy(i => i);
            
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            for (int i = 0; i < 100; i++)
            { list.Contains(923456); }
            sw.Stop();
            Console.WriteLine("Calling contains on the List 100 times cost " + sw.Elapsed.ToString());
            
            sw.Reset();
            sw.Start();
            for (int i = 0; i < 100; i++)
            { orderedList.Contains(923456); }
            sw.Stop();
            Console.WriteLine("Calling contains on the IOrderedEnumerable 100 times cost " + sw.Elapsed.ToString());
            
            Console.ReadKey();
        }
    }
}

那里没错...我正在建立一个包含一百万个(唯一)整数的列表.即使已经排序,我仍在调用 OrderBy扩展方法 [IOrderedEnumerable<int> [包含方法 [列表< T> [ IEnumerable< T>.包含扩展方法 [ ^ ].我希望这几乎与List<T>.Contains相同,后者正在扫描集合中的每个项目,直到找到我要寻找的项目为止.
现在不应该困难.但是结果让我感到非常惊讶!
List.Contains大约花费了0,7至0,8秒进行了100次迭代... IOrderedEnumerable.Contains花费了38秒!!!!
然后,我添加了这个小宝石:

Nothing wrong there... I am building a list with a million (unique) integers. Even though it is already sorted I am calling the OrderBy Extension Method[^] and I get an IOrderedEnumerable<int>[^].
Now I call the Contains Method[^] of the original list 100 times with a value of which I know will be somewhere at the back (assuming a List<T>[^] will scan every element until it finds the one I am looking for this will take almost the maximum amount of time to find it).
After that I do the same on the IOrderedEnumerable<T>, but I call the IEnumerable<T>.Contains Extension Method[^]. I am expecting that this will pretty much do the same as List<T>.Contains which is scanning every item in the collection until it finds the one I''m looking for.
Now that shouldn''t be to difficult. But I was pretty surprised by the result!
List.Contains took about 0,7 to 0,8 seconds for 100 iterations... IOrderedEnumerable.Contains took a whooping 38 seconds!!!
I then added this little gem:

sw.Reset();
sw.Start();
for (int i = 0; i < 100; i++)
{ orderedList.ToList().Contains(923456); }
sw.Stop();
Console.WriteLine("Calling contains on the IOrderedEnumerable.ToList 100 times cost " + sw.Elapsed.ToString());

花了40秒!以某种方式将列表复制100次并调用Contains仅比调用Contains ...花费2秒多的时间...
我还尝试将923456更改为1,以确保能够很快找到它,但实际上没有什么区别(尽管对于List<T>确实如此).
我感到震惊,震惊,惊讶和无知...

我在这里想念什么吗?我曾期望两个集合大约需要花费相同的时间来进行计算...实际上,由于订购了IOrderedEnumerable<T>,如果使用 EqualComparer [ ^ ].

有任何想法吗?我没有了...

And it took 40 seconds! Somehow copying the list 100 times and calling Contains only takes 2 seconds longer then only calling Contains...
I also tried changing 923456 to 1 to make sure it was found rather quickly, but it actually made no difference (it did for the List<T> though).
I am shocked, stunned, surprised and clueless...

Am I missing something here? I had expected both collections to take more or less the same time to compute... In fact, since an IOrderedEnumerable<T> is ordered it could find values MUCH faster if it searched using a Comparer[^] rather than an EqualityComparer[^].

Any idea''s? I''m out of them...

推荐答案

延迟执行是此处的罪魁祸首(我认为),直到枚举结果后,排序才会运行所以当你这样做的时候
Deferred execution is the culprit here (I think), the sort isn''t run until the result is enumerated so when you do this;
orderedList.Contains(923456); 



您会在每次迭代时再次使用该列表. ToList强制将结果枚举在前面.

您可以通过将排序方式更改为
来查看



you''re resorting the list again for every iteration. ToList forces the result to be enumerated up front.

You can see this by changing your sort to

IOrderedEnumerable<int> orderedList = list.OrderBy(i => { Console.WriteLine(" sorting=" + i); return i; });


(只需确保在一个非常小的列表上运行它即可:).

希望这会有所帮助,
弗雷德里克(Fredrik)


(just make sure to run that on a much, much smaller list :).

Hope this helps,
Fredrik


这篇关于关于IOrderedEnumerable的性能问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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