繁体   English   中英

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

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

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

总的来说慢一点。 LINQ的Count通常是O(N)操作,而List.CountArray.Length都保证为O(1)

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

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

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

在我的机器上:

  • 对于数组.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

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

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

一些额外的信息 - 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);
                }
            }
        }
    }

List.CountArray.Length确实比Linq Count()更快。 因为Linq Count()将迭代整个项目列表来计算。 List.CountArray.Length使用它们的属性。

暂无
暂无

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

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