I'm surprised that it apparently doesn't matter whether i prepend or append LINQ extension methods.
我很惊讶,无论我是在前置还是附加LINQ扩展方法都没关系。
Tested with Enumerable.FirstOrDefault
:
使用Enumerable.FirstOrDefault测试:
hugeList.Where(x => x.Text.Contains("10000")).FirstOrDefault();
- hugeList.Where(x => x.Text.Contains(“10000”))。FirstOrDefault();
-
hugeList.FirstOrDefault(x => x.Text.Contains("10000"));
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<1000;i++) hugeList.Where(x => x.Text.Contains("10000")).FirstOrDefault(); sw1.Stop(); sw2.Start(); for(int i=0;i<1000;i++) hugeList.FirstOrDefault(x => 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 < 1000; i++) hugeList.FirstOrDefault(x => x.Text.Contains("10000")); sw2.Stop(); sw1.Restart(); for (int i = 0; i < 1000; i++) hugeList.Where(x => 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)
I would have guessed that it would be slower to prepend Where
since it must find all matching items and then take the first and a preceded FirstOrDefault
could yield the first found item.
我会猜到前置它会慢一些因为它必须找到所有匹配的项目,然后取第一个和前面的FirstOrDefault可以产生第一个找到的项目。
Q: Can somebody explain why i'm on the wrong track?
问:有人可以解释我为什么走错了路吗?
2 个解决方案
#1
47
I would have guessed that it would be slower to prepend Where since it must find all matching items and then take the first and a preceded FirstOrDefault could yield the first found item. Can somebody explain why i'm on the wrong track?
我会猜到前置它会慢一些因为它必须找到所有匹配的项目,然后取第一个和前面的FirstOrDefault可以产生第一个找到的项目。有人能解释我为什么走错了路吗?
You are on the wrong track because your first statement is simply incorrect. Where
is not required to find all matching items before fetching the first matching item. Where
fetches matching items "on demand"; if you only ask for the first one, it only fetches the first one. If you only ask for the first two, it only fetches the first two.
你走错了路,因为你的第一个陈述是不正确的。在获取第一个匹配项之前,不需要在哪里找到所有匹配项。在哪里提取“按需”匹配项目;如果你只要求第一个,它只取出第一个。如果你只要求前两个,它只取前两个。
Jon Skeet does a nice bit on stage. Imagine you have three people. The first person has a shuffled pack of cards. The second person has a t-shirt that says "where card is red". The third person pokes the second person and says "give me the first card". The second person pokes the first person over and over again until the first person hands over a red card, which the second person then hands to the third person. The second person has no reason to keep poking the first person; the task is done!
Jon Skeet在舞台上做得很好。想象一下,你有三个人。第一个人有一副洗牌的卡片。第二个人有一件T恤,上面写着“卡片是红色的”。第三个人戳了第二个人说“给我第一张牌”。第二个人一遍又一遍地戳第一个人,直到第一个人交出红牌,然后第二个人交给第三个人。第二个人没有理由继续戳第一个人;任务完成了!
Now, if the second person's t-shirt says "order by rank ascending" then we have a very different situation. Now the second person really does need to get every card from the first person, in order to find the lowest card in the deck, before handing the first card to the third person.
现在,如果第二个人的T恤上写着“按等级递增排序”,那么我们就会有一个非常不同的情况。现在第二个人确实需要从第一个人那里获得每张卡,以便在将第一张卡交给第三人之前找到套牌中的最低牌。
This should now give you the necessary intuition to tell when order does matter for performance reasons. The net result of "give me the red cards and then sort them" is exactly the same as "sort all the cards then give me the red ones", but the former is much faster because you do not have to spend any time sorting the black cards that you are going to discard.
现在,这应该为您提供必要的直觉,以告知订单何时因性能原因而重要。 “给我红牌然后对它们进行排序”的最终结果与“对所有卡片进行排序然后给我红色的”完全相同,但前者更快,因为您不必花时间排序你要丢弃的黑卡。
#2
11
The Where()
method uses deferred execution and will provide the next matching item as it is requested. That is, Where()
does not evaluate and immediately return a sequence of all candidate objects, it provides them one at a time as they are iterated over.
Where()方法使用延迟执行,并在请求时提供下一个匹配项。也就是说,Where()不评估并立即返回所有候选对象的序列,它在迭代时一次提供一个。
Since FirstOrDefault()
stops after the first item, this will cause the Where()
to stop iterating as well.
由于FirstOrDefault()在第一个项目之后停止,因此这将导致Where()停止迭代。
Think of FirstOrDefault()
as halting the execution of the Where()
as if it performed a break
. It's not that simple, of course, but in essence since FirstOrDefault()
stops iterating once it finds an item, the Where()
does not need to proceed any further.
将FirstOrDefault()视为暂停执行Where(),就像执行中断一样。当然,这并不是那么简单,但实质上,因为FirstOrDefault()在找到项目后停止迭代,因此Where()不需要继续进行。
Of course, this is in the simple case of applying a FirstOrDefault()
on a Where()
clause, if you have other clauses in which imply the need to consider all items, this could have an effect, but this would be true both in using Where().FirstOrDefault()' combo or just
FirstOrDefault()' with a predicate.
当然,这是在Where()子句上应用FirstOrDefault()的简单情况,如果你有其他条款暗示需要考虑所有项目,这可能会产生影响,但这在使用Where()。FirstOrDefault()'combo或justFirstOrDefault()'和谓词。
#1
47
I would have guessed that it would be slower to prepend Where since it must find all matching items and then take the first and a preceded FirstOrDefault could yield the first found item. Can somebody explain why i'm on the wrong track?
我会猜到前置它会慢一些因为它必须找到所有匹配的项目,然后取第一个和前面的FirstOrDefault可以产生第一个找到的项目。有人能解释我为什么走错了路吗?
You are on the wrong track because your first statement is simply incorrect. Where
is not required to find all matching items before fetching the first matching item. Where
fetches matching items "on demand"; if you only ask for the first one, it only fetches the first one. If you only ask for the first two, it only fetches the first two.
你走错了路,因为你的第一个陈述是不正确的。在获取第一个匹配项之前,不需要在哪里找到所有匹配项。在哪里提取“按需”匹配项目;如果你只要求第一个,它只取出第一个。如果你只要求前两个,它只取前两个。
Jon Skeet does a nice bit on stage. Imagine you have three people. The first person has a shuffled pack of cards. The second person has a t-shirt that says "where card is red". The third person pokes the second person and says "give me the first card". The second person pokes the first person over and over again until the first person hands over a red card, which the second person then hands to the third person. The second person has no reason to keep poking the first person; the task is done!
Jon Skeet在舞台上做得很好。想象一下,你有三个人。第一个人有一副洗牌的卡片。第二个人有一件T恤,上面写着“卡片是红色的”。第三个人戳了第二个人说“给我第一张牌”。第二个人一遍又一遍地戳第一个人,直到第一个人交出红牌,然后第二个人交给第三个人。第二个人没有理由继续戳第一个人;任务完成了!
Now, if the second person's t-shirt says "order by rank ascending" then we have a very different situation. Now the second person really does need to get every card from the first person, in order to find the lowest card in the deck, before handing the first card to the third person.
现在,如果第二个人的T恤上写着“按等级递增排序”,那么我们就会有一个非常不同的情况。现在第二个人确实需要从第一个人那里获得每张卡,以便在将第一张卡交给第三人之前找到套牌中的最低牌。
This should now give you the necessary intuition to tell when order does matter for performance reasons. The net result of "give me the red cards and then sort them" is exactly the same as "sort all the cards then give me the red ones", but the former is much faster because you do not have to spend any time sorting the black cards that you are going to discard.
现在,这应该为您提供必要的直觉,以告知订单何时因性能原因而重要。 “给我红牌然后对它们进行排序”的最终结果与“对所有卡片进行排序然后给我红色的”完全相同,但前者更快,因为您不必花时间排序你要丢弃的黑卡。
#2
11
The Where()
method uses deferred execution and will provide the next matching item as it is requested. That is, Where()
does not evaluate and immediately return a sequence of all candidate objects, it provides them one at a time as they are iterated over.
Where()方法使用延迟执行,并在请求时提供下一个匹配项。也就是说,Where()不评估并立即返回所有候选对象的序列,它在迭代时一次提供一个。
Since FirstOrDefault()
stops after the first item, this will cause the Where()
to stop iterating as well.
由于FirstOrDefault()在第一个项目之后停止,因此这将导致Where()停止迭代。
Think of FirstOrDefault()
as halting the execution of the Where()
as if it performed a break
. It's not that simple, of course, but in essence since FirstOrDefault()
stops iterating once it finds an item, the Where()
does not need to proceed any further.
将FirstOrDefault()视为暂停执行Where(),就像执行中断一样。当然,这并不是那么简单,但实质上,因为FirstOrDefault()在找到项目后停止迭代,因此Where()不需要继续进行。
Of course, this is in the simple case of applying a FirstOrDefault()
on a Where()
clause, if you have other clauses in which imply the need to consider all items, this could have an effect, but this would be true both in using Where().FirstOrDefault()' combo or just
FirstOrDefault()' with a predicate.
当然,这是在Where()子句上应用FirstOrDefault()的简单情况,如果你有其他条款暗示需要考虑所有项目,这可能会产生影响,但这在使用Where()。FirstOrDefault()'combo或justFirstOrDefault()'和谓词。