LINQ Count()
方法是否比List<>.Count
或Array.Length
更快或更慢?
答案 0 :(得分:61)
一般情况下较慢。 LINQ的计数通常是O(N)
操作,而List.Count
和Array.Length
都保证为O(1)
。
然而,在某些情况下,LINQ将特殊情况IEnumerable<T>
参数转换为某些接口类型,例如IList<T>
或ICollection<T>
。然后,它将使用该Count方法执行实际的Count()
操作。所以它会回到O(1)
。但是你仍然需要支付演员和接口调用的小额开销。
答案 1 :(得分:25)
Enumerable.Count()
方法使用ICollection<T>
检查.Count
- 所以在数组和列表的情况下,效率并不高得多(只是额外的间接级别)。 / p>
答案 2 :(得分:22)
马克有正确的答案,但魔鬼在细节。
在我的机器上:
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.Count
或Array.Length
确实比Linq Count()
更快。因为Linq Count()
将迭代整个项目列表进行计数。 List.Count
或Array.Length
使用其财产。