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

时间:2009-06-11 14:00:00

标签: c# .net linq

LINQ Count()方法是否比List<>.CountArray.Length更快或更慢?

7 个答案:

答案 0 :(得分:61)

一般情况下较慢。 LINQ的计数通常是O(N)操作,而List.CountArray.Length都保证为O(1)

然而,在某些情况下,LINQ将特殊情况IEnumerable<T>参数转换为某些接口类型,例如IList<T>ICollection<T>。然后,它将使用该Count方法执行实际的Count()操作。所以它会回到O(1)。但是你仍然需要支付演员和接口调用的小额开销。

答案 1 :(得分:25)

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

答案 2 :(得分:22)

马克有正确的答案,但魔鬼在细节。

在我的机器上:

  • 对于数组.Length比.Count()
  • 快约100倍
  • 对于列表.Count比.Count()快10倍 - 注意:我希望实现IList<T>的所有集合的性能类似

由于.Length只涉及一个操作,因此数组启动较慢,数组上的.Count涉及一层间接。所以.Count on arrays开始慢了10倍(在我的机器上),这可能是接口明确实现的原因之一。想象一下,如果你有一个具有两个公共属性的对象,.Count和.Length。两者都完全相同,但.Count慢了10倍。

当然,非这一点确实有很大的不同,因为你必须计算你的数组并每秒列出数百万次才能感受到性能损失。

代码:

    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();
    }

结果:

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

答案 3 :(得分:2)

我相信如果你在ICollection或IList(比如ArrayList或List)上调用Linq.Count(),那么它只会返回Count属性的值。因此,普通系列的性能大致相同。

答案 4 :(得分:2)

我会说这取决于列表。如果它是一个IQueryable,它是某个db中的表,那么Count()将快得多,因为它不必加载所有对象。但是如果列表在内存中,我猜想如果不是大约相同的话,Count属性会更快。

答案 5 :(得分:0)

一些额外的信息 - LINQ Count - 使用它与否之间的区别可能很大 - 而且这也不必超过'大'集合。我有一个从linq到对象的集合,有大约6500个项目(大......但不是很大)。在我的情况下Count()需要几秒钟。转换为列表(或数组,无论如何),计数几乎是立即的。在内循环中计算这一点意味着影响可能很大。伯爵列举了一切。数组和列表都是“自我感知”它们的长度,不需要枚举它们。引用此count()的任何调试语句(ex4的log4net)也会使所有内容减慢得更多。帮自己一个忙,如果你需要引用它,经常保存计数大小,只在LINQ集合上调用一次,除非你把它转换成一个列表然后可以引用而不会影响性能。

这是对我上面谈到的内容的快速测试。注意每当我们调用Count()时我们的集合大小会发生变化..因此评估会发生,这不仅仅是预期的“计数”操作。需要注意的事项:)

    
    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);
                }
            }
        }
    }

答案 6 :(得分:0)

List.CountArray.Length确实比Linq Count()更快。因为Linq Count()将迭代整个项目列表进行计数。 List.CountArray.Length使用其财产。

相关问题