为啥 LINQ 中的 LastOrDefault(predicate) 比 FirstOrDefault(predicate) 快
Posted
技术标签:
【中文标题】为啥 LINQ 中的 LastOrDefault(predicate) 比 FirstOrDefault(predicate) 快【英文标题】:Why is LastOrDefault(predicate) in LINQ faster than FirstOrDefault(predicate)为什么 LINQ 中的 LastOrDefault(predicate) 比 FirstOrDefault(predicate) 快 【发布时间】:2020-01-02 18:21:54 【问题描述】:简介
今天在测试某些 LinQ 函数的性能差异时,我注意到 LastOrDefault(predicate)
几乎总是比 FirstOrDefault(predicate)
快,这让我有点感兴趣,所以我写了一些测试用例来测试这两个函数.
我创建了一个从 1 到 1 百万的 integer
值列表,如下所示:
List<int> l = new List<int>();
for (int i = 1; i <= 1000000; i++)
l.Add(i);
然后写了2个方法first()
和last()
static void first(List<int> l)
int e = l.FirstOrDefault(x => x == 500000);
int z = l.FirstOrDefault(x => x == 500000);
int d = l.FirstOrDefault(x => x == 500000);
int v = l.FirstOrDefault(x => x == 500000);
int f = l.FirstOrDefault(x => x == 500000);
我在 for 循环中运行了 1000 次,同时设置了一个断点,条件是在最后一次迭代后停止,但在我测试的每个单一情况下,LastOrDefault
都更快。
测试用例
两者都设置为列表中间的一个元素(LastOrDefault
的速度几乎是原来的两倍)
两者都设置为列表中具有相同距离的元素(如 250k 和 750k) - 同样LastOrDefault
更快
切换我的方法调用的顺序(在First()
之前调用Last()
)- 没有区别
使用各自的列表运行,而不是在同一个列表上运行(同样没有区别)
运行一个,关闭应用程序,重新打开,运行另一个(仍然LastOrDefault
更快)
将谓词设置为不在列表中的元素(仍然相同)
将谓词更改为多个符合条件的对象(仍然相同)
创建一个降序列表而不是一个升序列表(没有区别)
.Net Core 版本:3.0
由于调试器可能不准确,我再次尝试使用此代码:
Console.WriteLine(DateTime.Now + ":" + DateTime.Now.Millisecond);
for (int i = 0; i < 1000; i++)
first(l);
Console.WriteLine(DateTime.Now + ":" + DateTime.Now.Millisecond);
for (int i = 0; i < 1000; i++)
last(l);
Console.WriteLine(DateTime.Now + ":" + DateTime.Now.Millisecond);
FirstOrDefault
也返回 34 秒,LastOrDefault
也返回 23 秒
问题
为什么LastOrDefault
在我所有的测试用例中都比FirstOrDefault
快得多?
【问题讨论】:
结果到底是什么?你是怎么测试的?是否留出了热身时间? 由于可枚举是一个列表,我非常怀疑您在列表中行走的方向是否存在任何性能差异。它是0..end
或end..0
。没有别的了。
可能是因为 FirstOrDefault 使用了枚举器和 MoveNext,而 LastOrDefault 使用了逆 for 循环(用于 List)。实际上取决于类型以及它是否具有谓词。
@Patrick Hofman 我设置了一个 net Core Console 应用程序,填充列表,然后设置断点,然后在 for 循环中调用这两个方法 1000 次,并在到达时花费了我的调试器返回的时间最后一次迭代,“FirstOrDefault”为 32.8 秒,“LastOrDefault”为 16.7 秒 @Caramiriel 添加了网络核心信息
@steve16351 我想这一定是它。 .NET Standard 没有 Last
的优化,Last
所用的时间大约是您预期的两倍,但我认为与 .NET Core 中的 OP 相同。
【参考方案1】:
steve16351 在已删除的评论中指出,在 .NET Core 中,Last
具有以下优化:
if (source is IList<TSource> list)
for (int i = list.Count - 1; i >= 0; --i)
TSource result = list[i];
if (predicate(result))
found = true;
return result;
但First
没有并最终运行:
foreach (TSource element in source)
if (predicate(element))
found = true;
return element;
很可能通过索引器访问列表元素比使用foreach
和迭代器更快。相比之下,.NET Standard 没有针对 Last
进行这种优化,而是遍历完整的输入,并且 Last
的运行速度比您预期的 First
慢。
【讨论】:
哦。我已经很奇怪为什么他的评论消失得这么快,看起来他是对的,但是当我重新加载页面时它就消失了。谢谢。【参考方案2】:我尝试执行 ExecuteFirst
和 ExecuteLast
甚至更改它们的执行顺序,而 LastOrDefault
总是比 FirstOrDefault
多。
class Program
static void Main(string[] args)
List<int> numbers = new List<int>();
for (int i = 1; i <= 1000000; i++)
numbers.Add(i);
for (int i = 1; i <= 100; i++)
Stopwatch stopwatch = new Stopwatch();
ExecuteFirst(ref stopwatch, ref numbers);
stopwatch.Reset();
ExecuteLast(ref stopwatch, ref numbers);
for (int i = 1; i <= 100; i++)
Stopwatch stopwatch = new Stopwatch();
ExecuteLast(ref stopwatch, ref numbers);
stopwatch.Reset();
ExecuteFirst(ref stopwatch, ref numbers);
private static void ExecuteFirst(ref Stopwatch stopwatch, ref List<int> numbers)
stopwatch.Start();
int first = numbers.FirstOrDefault(x => x == 500000);
stopwatch.Stop();
Console.WriteLine("First: " + stopwatch.Elapsed);
private static void ExecuteLast(ref Stopwatch stopwatch, ref List<int> numbers)
stopwatch.Start();
int last = numbers.LastOrDefault(x => x == 500000);
stopwatch.Stop();
Console.WriteLine("Last: " + stopwatch.Elapsed);
ExecuteFirst then ExecuteLast
版本的输出:
First: 00:00:00.0056298 Last: 00:00:00.0089494 First: 00:00:00.0039494 Last: 00:00:00.0084491 First: 00:00:00.0041225 Last: 00:00:00.0087664 First: 00:00:00.0039685 Last: 00:00:00.0083576 First: 00:00:00.0064472 Last: 00:00:00.0109716 First: 00:00:00.0041366 Last: 00:00:00.0111575 First: 00:00:00.0039746 Last: 00:00:00.0085590 First: 00:00:00.0040453 Last: 00:00:00.0083751 First: 00:00:00.0057352 Last: 00:00:00.0090655 First: 00:00:00.0041225 Last: 00:00:00.0081635 First: 00:00:00.0042336 Last: 00:00:00.0085277 First: 00:00:00.0038742 Last: 00:00:00.0088863 First: 00:00:00.0039309 Last: 00:00:00.0141321 First: 00:00:00.0044766 Last: 00:00:00.0088888 First: 00:00:00.0044096 Last: 00:00:00.0147227 First: 00:00:00.0042950 Last: 00:00:00.0177956 First: 00:00:00.0064265 Last: 00:00:00.0158906 First: 00:00:00.0051914 Last: 00:00:00.0177836 First: 00:00:00.0067148 Last: 00:00:00.0123487 First: 00:00:00.0045096 Last: 00:00:00.0113824 First: 00:00:00.0040213 Last: 00:00:00.0145903 First: 00:00:00.0061554 Last: 00:00:00.0123555 First: 00:00:00.0047815 Last: 00:00:00.0119132 First: 00:00:00.0055103 Last: 00:00:00.0141871 First: 00:00:00.0069865 Last: 00:00:00.0115481 First: 00:00:00.0052736 Last: 00:00:00.0167697 First: 00:00:00.0062566 Last: 00:00:00.0111363 First: 00:00:00.0051245 Last: 00:00:00.0120161 First: 00:00:00.0044649 Last: 00:00:00.0086359 First: 00:00:00.0039902 Last: 00:00:00.0089326 First: 00:00:00.0070409 Last: 00:00:00.0093965 First: 00:00:00.0047403 Last: 00:00:00.0143759 First: 00:00:00.0052523 Last: 00:00:00.0105465 First: 00:00:00.0072541 Last: 00:00:00.0113418 First: 00:00:00.0064120 Last: 00:00:00.0139322 First: 00:00:00.0062902 Last: 00:00:00.0173657 First: 00:00:00.0068329 Last: 00:00:00.0163935 First: 00:00:00.0056465 Last: 00:00:00.0100116 First: 00:00:00.0057379 Last: 00:00:00.0084148 First: 00:00:00.0058303 Last: 00:00:00.0167930 First: 00:00:00.0065232 Last: 00:00:00.0100014 First: 00:00:00.0039309 Last: 00:00:00.0093778 First: 00:00:00.0047291 Last: 00:00:00.0133724 First: 00:00:00.0044344 Last: 00:00:00.0095120 First: 00:00:00.0044793 Last: 00:00:00.0083334 First: 00:00:00.0048849 Last: 00:00:00.0091849 First: 00:00:00.0042633 Last: 00:00:00.0095615 First: 00:00:00.0074706 Last: 00:00:00.0081830 First: 00:00:00.0046968 Last: 00:00:00.0086369 First: 00:00:00.0055665 Last: 00:00:00.0088337 First: 00:00:00.0045883 Last: 00:00:00.0112508 First: 00:00:00.0078855 Last: 00:00:00.0149504 First: 00:00:00.0065615 Last: 00:00:00.0102155 First: 00:00:00.0046303 Last: 00:00:00.0104928 First: 00:00:00.0063564 Last: 00:00:00.0119335 First: 00:00:00.0048461 Last: 00:00:00.0092795 First: 00:00:00.0042306 Last: 00:00:00.0090954 First: 00:00:00.0042236 Last: 00:00:00.0090376 First: 00:00:00.0039102 Last: 00:00:00.0087163 First: 00:00:00.0047897 Last: 00:00:00.0093651 First: 00:00:00.0051779 Last: 00:00:00.0101453 First: 00:00:00.0041795 Last: 00:00:00.0086312 First: 00:00:00.0039371 Last: 00:00:00.0087337 First: 00:00:00.0048348 Last: 00:00:00.0114352 First: 00:00:00.0049419 Last: 00:00:00.0134430 First: 00:00:00.0063191 Last: 00:00:00.0096597 First: 00:00:00.0041087 Last: 00:00:00.0100510 First: 00:00:00.0055977 Last: 00:00:00.0122221 First: 00:00:00.0046453 Last: 00:00:00.0097579 First: 00:00:00.0050965 Last: 00:00:00.0108959 First: 00:00:00.0061811 Last: 00:00:00.0093178 First: 00:00:00.0060297 Last: 00:00:00.0085977 First: 00:00:00.0040451 Last: 00:00:00.0114430 First: 00:00:00.0046424 Last: 00:00:00.0118572 First: 00:00:00.0064396 Last: 00:00:00.0147170 First: 00:00:00.0052414 Last: 00:00:00.0108874 First: 00:00:00.0045109 Last: 00:00:00.0082625 First: 00:00:00.0044640 Last: 00:00:00.0136483 First: 00:00:00.0049840 Last: 00:00:00.0087787 First: 00:00:00.0049482 Last: 00:00:00.0138222 First: 00:00:00.0055885 Last: 00:00:00.0109636 First: 00:00:00.0052437 Last: 00:00:00.0130392 First: 00:00:00.0053844 Last: 00:00:00.0103824 First: 00:00:00.0062271 Last: 00:00:00.0125599 First: 00:00:00.0043152 Last: 00:00:00.0091548 First: 00:00:00.0059537 Last: 00:00:00.0125432 First: 00:00:00.0057340 Last: 00:00:00.0099097 First: 00:00:00.0052127 Last: 00:00:00.0087050 First: 00:00:00.0045914 Last: 00:00:00.0095816 First: 00:00:00.0065290 Last: 00:00:00.0090501 First: 00:00:00.0045474 Last: 00:00:00.0108880 First: 00:00:00.0054650 Last: 00:00:00.0092074 First: 00:00:00.0042946 Last: 00:00:00.0129336 First: 00:00:00.0045581 Last: 00:00:00.0172552 First: 00:00:00.0058246 Last: 00:00:00.0080876 First: 00:00:00.0040249 Last: 00:00:00.0112583 First: 00:00:00.0047926 Last: 00:00:00.0085989 First: 00:00:00.0045357 Last: 00:00:00.0088068 First: 00:00:00.0039247 Last: 00:00:00.0094145 First: 00:00:00.0039182 Last: 00:00:00.0085856
ExecuteLast then ExecuteFirst
版本的输出:
Last: 00:00:00.0087140 First: 00:00:00.0045242 Last: 00:00:00.0082524 First: 00:00:00.0040122 Last: 00:00:00.0081924 First: 00:00:00.0039598 Last: 00:00:00.0081365 First: 00:00:00.0041632 Last: 00:00:00.0087045 First: 00:00:00.0040455 Last: 00:00:00.0082440 First: 00:00:00.0041200 Last: 00:00:00.0082281 First: 00:00:00.0041470 Last: 00:00:00.0087138 First: 00:00:00.0039467 Last: 00:00:00.0082286 First: 00:00:00.0099966 Last: 00:00:00.0159285 First: 00:00:00.0059864 Last: 00:00:00.0103221 First: 00:00:00.0045370 Last: 00:00:00.0102541 First: 00:00:00.0042682 Last: 00:00:00.0081628 First: 00:00:00.0062049 Last: 00:00:00.0130017 First: 00:00:00.0046107 Last: 00:00:00.0146495 First: 00:00:00.0060628 Last: 00:00:00.0140509 First: 00:00:00.0042348 Last: 00:00:00.0087499 First: 00:00:00.0043035 Last: 00:00:00.0119328 First: 00:00:00.0053357 Last: 00:00:00.0095866 First: 00:00:00.0081749 Last: 00:00:00.0157497 First: 00:00:00.0065187 Last: 00:00:00.0165949 First: 00:00:00.0062613 Last: 00:00:00.0139213 First: 00:00:00.0058088 Last: 00:00:00.0121819 First: 00:00:00.0054371 Last: 00:00:00.0095390 First: 00:00:00.0070151 Last: 00:00:00.0110936 First: 00:00:00.0073251 Last: 00:00:00.0104844 First: 00:00:00.0058563 Last: 00:00:00.0131254 First: 00:00:00.0064146 Last: 00:00:00.0100039 First: 00:00:00.0045887 Last: 00:00:00.0102629 First: 00:00:00.0051754 Last: 00:00:00.0086035 First: 00:00:00.0041619 Last: 00:00:00.0104485 First: 00:00:00.0055513 Last: 00:00:00.0097863 First: 00:00:00.0047921 Last: 00:00:00.0097700 First: 00:00:00.0049790 Last: 00:00:00.0129902 First: 00:00:00.0049853 Last: 00:00:00.0090255 First: 00:00:00.0044574 Last: 00:00:00.0085991 First: 00:00:00.0061191 Last: 00:00:00.0144359 First: 00:00:00.0048091 Last: 00:00:00.0133516 First: 00:00:00.0056255 Last: 00:00:00.0084006 First: 00:00:00.0063759 Last: 00:00:00.0193624 First: 00:00:00.0062311 Last: 00:00:00.0176409 First: 00:00:00.0069601 Last: 00:00:00.0168154 First: 00:00:00.0069095 Last: 00:00:00.0099649 First: 00:00:00.0057600 Last: 00:00:00.0087139 First: 00:00:00.0040068 Last: 00:00:00.0085248 First: 00:00:00.0061416 Last: 00:00:00.0085084 First: 00:00:00.0043856 Last: 00:00:00.0089587 First: 00:00:00.0044830 Last: 00:00:00.0093276 First: 00:00:00.0043679 Last: 00:00:00.0110072 First: 00:00:00.0042437 Last: 00:00:00.0126469 First: 00:00:00.0042610 Last: 00:00:00.0112851 First: 00:00:00.0044525 Last: 00:00:00.0146068 First: 00:00:00.0067056 Last: 00:00:00.0126607 First: 00:00:00.0048659 Last: 00:00:00.0083654 First: 00:00:00.0062265 Last: 00:00:00.0097216 First: 00:00:00.0061381 Last: 00:00:00.0089756 First: 00:00:00.0042742 Last: 00:00:00.0106504 First: 00:00:00.0059941 Last: 00:00:00.0129825 First: 00:00:00.0052327 Last: 00:00:00.0086158 First: 00:00:00.0048668 Last: 00:00:00.0087767 First: 00:00:00.0040427 Last: 00:00:00.0097813 First: 00:00:00.0042703 Last: 00:00:00.0086771 First: 00:00:00.0051560 Last: 00:00:00.0097772 First: 00:00:00.0051117 Last: 00:00:00.0086385 First: 00:00:00.0050181 Last: 00:00:00.0092713 First: 00:00:00.0044719 Last: 00:00:00.0094507 First: 00:00:00.0041345 Last: 00:00:00.0090835 First: 00:00:00.0041929 Last: 00:00:00.0101841 First: 00:00:00.0045660 Last: 00:00:00.0132945 First: 00:00:00.0042977 Last: 00:00:00.0102504 First: 00:00:00.0041772 Last: 00:00:00.0087283 First: 00:00:00.0058613 Last: 00:00:00.0095019 First: 00:00:00.0058306 Last: 00:00:00.0098703 First: 00:00:00.0062143 Last: 00:00:00.0143740 First: 00:00:00.0058965 Last: 00:00:00.0146650 First: 00:00:00.0049196 Last: 00:00:00.0101419 First: 00:00:00.0045298 Last: 00:00:00.0096505 First: 00:00:00.0047797 Last: 00:00:00.0107579 First: 00:00:00.0059183 Last: 00:00:00.0126266 First: 00:00:00.0055267 Last: 00:00:00.0126165 First: 00:00:00.0054118 Last: 00:00:00.0120701 First: 00:00:00.0051365 Last: 00:00:00.0153770 First: 00:00:00.0053540 Last: 00:00:00.0153887 First: 00:00:00.0070967 Last: 00:00:00.0130810 First: 00:00:00.0058005 Last: 00:00:00.0099139 First: 00:00:00.0045073 Last: 00:00:00.0086909 First: 00:00:00.0050152 Last: 00:00:00.0092414 First: 00:00:00.0045098 Last: 00:00:00.0081899 First: 00:00:00.0039903 Last: 00:00:00.0088524 First: 00:00:00.0044292 Last: 00:00:00.0085165 First: 00:00:00.0041663 Last: 00:00:00.0079039 First: 00:00:00.0040911 Last: 00:00:00.0083395 First: 00:00:00.0041872 Last: 00:00:00.0093267 First: 00:00:00.0041617 Last: 00:00:00.0092689 First: 00:00:00.0042109 Last: 00:00:00.0088358 First: 00:00:00.0041233 Last: 00:00:00.0081352 First: 00:00:00.0046823 Last: 00:00:00.0085252 First: 00:00:00.0042007 Last: 00:00:00.0083383 First: 00:00:00.0041155 Last: 00:00:00.0096344 First: 00:00:00.0046664 Last: 00:00:00.0110845 First: 00:00:00.0047776
【讨论】:
以上是关于为啥 LINQ 中的 LastOrDefault(predicate) 比 FirstOrDefault(predicate) 快的主要内容,如果未能解决你的问题,请参考以下文章
用于从 LastOrDefault 父项中查找子项的实体框架 LINQ
First 和 FirstOrDefault , Last 和 LastOrDefault 有啥区别 [重复]
LINQ查询操作符之FirstFirstOrDefaultLastLastOrDefaultElementAtElementAtOrDefaultContainsAnyAllCoun
LINQ查询操作符之FirstFirstOrDefaultLastLastOrDefaultElementAtElementAtOrDefaultContainsAnyAllCoun
LINQ查询操作符之FirstFirstOrDefaultLastLastOrDefaultElementAtElementAtOrDefaultContainsAnyAllCoun