简体   繁体   English

Linq Count() 比 List.Count 或 Array.Length 快还是慢?

[英]Is the Linq Count() faster or slower than List.Count or Array.Length?

Is the LINQ Count() method any faster or slower than List<>.Count or Array.Length ? LINQ Count()方法是否比List<>.CountArray.Length更快或更慢?

In general Slower. 总的来说慢一点。 LINQ's Count in general is an O(N) operation while List.Count and Array.Length are both guaranteed to be O(1) . LINQ的Count通常是O(N)操作,而List.CountArray.Length都保证为O(1)

However it some cases LINQ will special case the IEnumerable<T> parameter by casting to certain interface types such as IList<T> or ICollection<T> . 但是在某些情况下,LINQ将特殊情况下的IEnumerable<T>参数转换为某些接口类型,例如IList<T>ICollection<T> It will then use that Count method to do an actual Count() operation. 然后,它将使用该Count方法执行实际的Count()操作。 So it will go back down to O(1) . 所以它会回到O(1) But you still pay the minor overhead of the cast and interface call. 但是你仍然需要支付演员和接口调用的小额开销。

Enumerable.Count()方法使用.Count检查ICollection<T> - 因此在数组和列表的情况下,它的效率并不高得多(只是一个额外的间接级别)。

Marc has the right answer but the devil is in the detail. 马克有正确的答案,但魔鬼在细节。

On my machine: 在我的机器上:

  • For arrays .Length is about 100 times faster than .Count() 对于数组.Length比.Count()快约100倍
  • For Lists .Count is about 10 times faster than .Count() - Note: I would expect similar performance from all Collections that implement IList<T> 对于列表.Count比.Count()快10倍 - 注意:我希望所有实现IList<T>集合的性能类似

Arrays start off slower since .Length involves only a single operation, .Count on arrays involves a layer of indirection. 由于.Length只涉及一个操作,因此数组启动速度较慢,数组上的.Count涉及一个间接层。 So .Count on arrays starts off 10x slower (on my machine), which could be one of those reasons the interface is implemented explicitly. 所以.Count on arrays开始慢了10倍(在我的机器上),这可能是接口明确实现的原因之一。 Imagine if you had an object with two public properties, .Count and .Length. 想象一下,如果你有一个具有两个公共属性的对象,.Count和.Length。 Both do the exact same thing but .Count is 10X slower. 两者都完全相同,但.Count慢了10倍。

Of course non of this really makes much of a difference since you would have to be counting your arrays and lists millions of times a second to feel a performance hit. 当然,由于您必须对数组进行计数并且每秒列出数百万次才能感觉到性能受到影响,因此非实际情况确实存在很大差异。

Code: 码:

    static void TimeAction(string description, int times, Action func) {
        var watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < times; i++) {
            func();
        }
        watch.Stop();
        Console.Write(description);
        Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
    } 

    static void Main(string[] args) {
        var array = Enumerable.Range(0, 10000000).ToArray();
        var list = Enumerable.Range(0, 10000000).ToArray().ToList();

        // jit
        TimeAction("Ignore and jit", 1 ,() =>
        {
            var junk = array.Length;
            var junk2 = list.Count;
            array.Count();
            list.Count();
        });


        TimeAction("Array Length", 1000000, () => {
            var tmp1 = array.Length;
        });

        TimeAction("Array Count()", 1000000, () =>
        {
            var tmp2 = array.Count();
        });

        TimeAction("Array Length through cast", 1000000, () =>
        {
            var tmp3 = (array as ICollection<int>).Count;
        });


        TimeAction("List Count", 1000000, () =>
        {
            var tmp1 = list.Count;
        });

        TimeAction("List Count()", 1000000, () =>
        {
            var tmp2 = list.Count();
        });

        Console.ReadKey();
    }

Results: 结果:

Array Length Time Elapsed 3 ms
Array Count() Time Elapsed 264 ms
Array Length through cast Time Elapsed 16 ms
List Count Time Elapsed 3 ms
List Count() Time Elapsed 18 ms

I believe that if you call Linq.Count() on either an ICollection or IList (like an ArrayList or List) then it will just return the Count property's value. 我相信如果你在ICollection或IList(如ArrayList或List)上调用Linq.Count(),那么它将只返回Count属性的值。 So the performance will be about the same on plain collections. 因此,普通集合的性能大致相同。

I would say it depends on the List. 我会说它取决于列表。 If it is an IQueryable that is a table in a db somewhere then Count() will be much faster because it doesn't have to load all of the objects. 如果它是一个IQueryable,它是某个db中的表,那么Count()会更快,因为它不必加载所有对象。 But if the list is in-memory i would guess that the Count property would be faster if not about the same. 但是如果列表在内存中,我猜想如果不是大约相同的话,Count属性会更快。

Some additional info - LINQ Count - the difference between using it and not can be huge - and this doesn't have to be over 'large' collections either. 一些额外的信息 - LINQ Count - 使用它与否之间的区别可能很大 - 而且这也不必超过'大'集合。 I have a collection formed from linq to objects with about 6500 items (big.. but not huge by any means) . 我有一个从linq到对象的集合,有大约6500个项目(大......但不是很大)。 Count() in my case takes several seconds. 在我的情况下Count()需要几秒钟。 Converting to a list (or array, whatver) the count is then virtually immediate. 转换为列表(或数组,无论如何),计数几乎是立即的。 Having this count in an inner loop means the impact could be huge. 在内循环中计算这一点意味着影响可能很大。 Count enumerates through everything. 伯爵列举了一切。 An array and a list are both 'self aware' of their lengths and do not need to enumerate them. 数组和列表都是“自我感知”它们的长度,不需要枚举它们。 Any debug statements (log4net for ex) that reference this count() will also then slow everything down considerably more. 引用此count()的任何调试语句(ex4的log4net)也会使所有内容减慢得更多。 Do yourself a favor and if you need to reference this often save the count size and only call it once on a LINQ collection unless you convert it to a list and then can reference away without a performance hit. 帮自己一个忙,如果你需要引用它,经常保存计数大小,只在LINQ集合上调用一次,除非你把它转换成一个列表,然后可以引用而不会影响性能。

Here is a quick test of what I was talking about above. 这是对我上面所说的内容的快速测试。 Note every time we call Count() our collection size changes.. hence evaluation happens, which is more than an expected 'count' operation. 注意每当我们调用Count()时我们的集合大小会发生变化..因此评估会发生,这不仅仅是预期的“计数”操作。 Just something to be aware of : ) 需要注意的事情:)

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

    namespace LinqTest
    {
        class TestClass
        {
            public TestClass()
            {
                CreateDate = DateTime.Now;
            }
            public DateTime CreateDate;
        }

        class Program
        {

            static void Main(string[] args)
            {
                //Populate the test class
                List list = new List(1000);
                for (int i=0; i<1000; i++)
                {
                    System.Threading.Thread.Sleep(20);
                    list.Add(new TestClass());
                    if(i%100==0)
                    { 
                        Console.WriteLine(i.ToString() +  " items added");
                    }
                }

                //now query for items 
                var newList = list.Where(o=> o.CreateDate.AddSeconds(5)> DateTime.Now);
                while (newList.Count() > 0)
                {
                    //Note - are actual count keeps decreasing.. showing our 'execute' is running every time we call count.
                    Console.WriteLine(newList.Count());
                    System.Threading.Thread.Sleep(500);
                }
            }
        }
    }

List.Count or Array.Length is indeed faster than Linq Count() . List.CountArray.Length确实比Linq Count()更快。 Because Linq Count() will iterate through the whole list of items to count. 因为Linq Count()将迭代整个项目列表来计算。 List.Count or Array.Length use their property. List.CountArray.Length使用它们的属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM