i saw today a linq query syntax in my project which was counting from List
items on specifc condition this way:
int temp = (from A in pTasks
where A.StatusID == (int)BusinessRule.TaskStatus.Pending
select A).ToList().Count();
i thought to refactor it by writing it like using Count()
to make more readable and what i thought was it would be performance wise also good, so i wrote:
int UnassignedCount = pTasks.Count(x => x.StatusID == (int)BusinessRule.TaskStatus.Pending);
But when i checked by putting StopWatch
the Time Elapsed by the lambda expression is always more than the query synax:
Stopwatch s = new Stopwatch();
s.Start();
int UnassignedCount = pTasks.Count(x => x.StatusID == (int)BusinessRule.TaskStatus.Pending);
s.Stop();
Stopwatch s2 = new Stopwatch();
s2.Start();
int temp = (from A in pTasks
where A.StatusID == (int)BusinessRule.TaskStatus.Pending
select A).ToList().Count();
s2.Stop();
Can somebody explain why is it so?
I have simulated your situation. And yes, there is difference between execution times of these queries. But, the reason of this difference isn't syntax of the query. It doesn't matter if you have used method or query syntax. Both yields the same result because query expressions are translated into their lambda expressions before they’re compiled.
But, if you have paid attention the two queries aren't same at all.Your second query will be translated to it's lambda syntax before it's compiled (You can remove
ToList()
from query, because it is redundant):And now we have two Linq queries in lambda syntax. The one I have stated above and this:
Now, the question is:
Why there is difference between execution times of these two queries?
Let's find the answer:
We can understand the reason of this difference by reviewing these:
-
.Where(this IEnumerable<TSource> source, Func<TSource, bool> predicate).Count(this IEnumerable<TSource> source)
and
-
Count(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
;Here is the implementation of
Count(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
:And here is the
Where(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
:Let's pay an attention to
Where()
implementation. It will returnWhereListIterator()
if your collection is List, butCount()
will just iterate over source. And in my opinion they have made some speed up in the implementation ofWhereListIterator
. And after this we are callingCount()
method which takes no predicate as input and only will iterate on filtered collection.And regarding to that speed up in the implementation of
WhereListIterator
:I have found this question in SO: LINQ performance Count vs Where and Count. You can read @Matthew Watson answer there. He explains the performance difference between these two queries. And the result is: The
Where
iterator avoids indirect virtual table call, but calls iterator methods directly. As you see in that answercall
instruction will be emitted instead ofcallvirt
. And,callvirt
is slower thancall
:From book
CLR via C#
:Like Farhad said, the implementation of Where(x).Count() and Count(x) vary. The first one instantiates an additional iterator, which on my pc costs about 30.000 ticks (regardless of the collection size)
Also, ToList is not free. It allocates memory. It costs time. On my pc, it roughly doubles execution time. (so linear dependent op the collection size)
Also, debugging requires spin-up time. So it's difficult to acurately measure performace in one go. I'd recommend a loop like this example. Then, ignore the first set of results.