Is the Linq Count() faster or slower than List.Count or Array.Length?
linq-
一般来说,速度较慢。Linq的计数一般是一个
但是,在某些情况下,Linq会通过将参数强制转换为某些接口类型(如
马克有正确的答案,但魔鬼在细节上。
在我的机器上:
- 对于数组。长度大约比.count()快100倍
- 对于lists.count比.count()快10倍-注意:我希望实现
IList 的所有集合都有类似的性能。
数组的开始速度较慢,因为.length只涉及一个操作,.count on array涉及一个间接层。所以,数组的计数开始时慢了10倍(在我的机器上),这可能是接口显式实现的原因之一。想象一下,如果有一个对象有两个公共属性,.count和.length。两个都做同样的事情,但是计数慢了10倍。
当然,如果不这样做,确实会有很大的不同,因为您必须计算数组并每秒列出数百万次才能感觉到性能受到影响。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 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(); } |
结果:
1 2 3 4 5 | 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 |
我认为这取决于清单。如果它是一个IQueryable,它是数据库中某个地方的一个表,那么count()将更快,因为它不需要加载所有的对象。但是,如果列表在内存中,我想Count属性会更快,如果不是相同的话。
我相信,如果您对ICollection或IList(如ArrayList或List)调用Linq.Count(),那么它将只返回Count属性的值。因此,在普通集合中的性能将大致相同。
一些额外的信息——linq计数——使用它和不使用它之间的区别可能很大——而且这也不一定要超过"大"集合。我有一个从LINQ到对象的集合,大约有6500个项目(大……但无论如何都不是很大)。在我的例子中,count()需要几秒钟。转换成一个列表(或数组,whatver),计数实际上是即时的。在一个内部循环中使用这个计数意味着影响可能很大。计数枚举所有内容。数组和列表都是对其长度的"自我感知",不需要枚举它们。引用此count()的任何调试语句(log4net for ex)也会大大降低速度。帮你自己一个忙,如果你需要引用它,通常会保存计数大小,并且在一个LINQ集合中只调用它一次,除非你将它转换为一个列表,然后可以引用掉而不影响性能。
这是我刚才所说的一个快速测试。注意,每次调用count()时,集合大小都会发生变化。因此会发生评估,这超出了预期的"count"操作。只是需要注意的事情:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 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); } } } } </wyn> |