LINQ扩展方法的顺序不影响性能?
我很惊讶,无论我是在前置还是附加LINQ扩展方法都没关系。
使用Enumerable.FirstOrDefault
测试:
-
hugeList.Where(x => x.Text.Contains("10000")).FirstOrDefault();
-
hugeList.FirstOrDefault(x => x.Text.Contains("10000"));
var hugeList = Enumerable.Range(1, 50000000) .Select(i => new { ID = i, Text = "Item" + i }); var sw1 = new System.Diagnostics.Stopwatch(); var sw2 = new System.Diagnostics.Stopwatch(); sw1.Start(); for(int i=0;i x.Text.Contains("10000")).FirstOrDefault(); sw1.Stop(); sw2.Start(); for(int i=0;i x.Text.Contains("10000")); sw2.Stop(); var result1 = String.Format("FirstOrDefault after: {0} FirstOrDefault before: {1}", sw1.Elapsed, sw2.Elapsed); //result1: FirstOrDefault after: 00:00:03.3169683 FirstOrDefault before: 00:00:03.0463219 sw2.Restart(); for (int i = 0; i x.Text.Contains("10000")); sw2.Stop(); sw1.Restart(); for (int i = 0; i x.Text.Contains("10000")).FirstOrDefault(); sw1.Stop(); var result2 = String.Format("FirstOrDefault before: {0} FirstOrDefault after: {1}", sw2.Elapsed, sw1.Elapsed); //result2: FirstOrDefault before: 00:00:03.6833079 FirstOrDefault after: 00:00:03.1675611 //average after:3.2422647 before: 3.3648149 (all seconds)
我会猜到前置它会慢一些因为它必须找到所有匹配的项目,然后取第一个和前面的FirstOrDefault
可以产生第一个找到的项目。
问:有人可以解释我为什么走错了路吗?
我会猜到前置它会慢一些因为它必须找到所有匹配的项目,然后取第一个和前面的FirstOrDefault可以产生第一个找到的项目。 有人能解释我为什么走错了路吗?
你走错了路,因为你的第一个陈述是不正确的。 Where
获取第一个匹配项之前,不需要Where
找到所有匹配项。 Where
提取“按需”匹配项目; 如果你只要求第一个,它只取出第一个。 如果你只要求前两个,它只取前两个。
Jon Skeet在舞台上做得很好。 想象一下,你有三个人。 第一个人有一副洗牌的卡片。 第二个人有一件T恤,上面写着“卡片是红色的”。 第三个人戳了第二个人说“给我第一张牌”。 第二个人一遍又一遍地戳第一个人, 直到第一个人交出红牌,然后第二个人交给第三个人。 第二个人没有理由继续戳第一个人; 任务完成了!
现在,如果第二个人的T恤上写着“按等级递增排序”,那么我们就会有一个非常不同的情况。 现在第二个人确实需要从第一个人那里获得每张卡,以便在将第一张卡交给第三人之前找到套牌中的最低牌。
现在,这应该为您提供必要的直觉,以告知订单何时因性能原因而重要。 “给我红牌然后对它们进行排序”的最终结果与“对所有卡片进行排序然后给我红色的”完全相同,但前者更快,因为您不必花时间排序你要丢弃的黑卡。
Where()
方法使用延迟执行,并在请求时提供下一个匹配项。 也就是说, Where()
不评估并立即返回所有候选对象的序列,它在迭代时一次提供一个。
由于FirstOrDefault()
在第一个项目之后停止,因此这将导致Where()
停止迭代。
将FirstOrDefault()
视为暂停执行Where()
,就像执行break
。 当然,这并不是那么简单,但实质上,因为FirstOrDefault()
在找到项目后停止迭代,因此Where()
不需要继续进行。
当然,这是在Where()
子句上应用FirstOrDefault()
的简单情况,如果你有其他条款暗示需要考虑所有项目,这可能会产生影响,但这在使用Where().FirstOrDefault()' combo or just
带有谓词的FirstOrDefault()’。
- 无法将类型为“object {System.Collections.Generic.List }”的对象强制转换为ICollection
- Scaffolding EntityFramework 6无法将’System.Data.Entity.Core.Objects.ObjectContext’类型的对象强制转换为’System.Data.Objects.ObjectContext’
- 线程安全类应该在其构造函数的末尾有一个内存屏障吗?
- 这个初始化方法有什么区别?
- 如何在序列化对象时加密选定的属性?
- 在C#中将SID转换为用户名
- 我如何使用Activator.CreateInstance与字符串?
- 紧凑框架中的透明度
- 将DB Connection对象传递给方法