1

I like anonymous lambdas; they let you concisely express complex selects from lists. LINQ does something similar, so I thought I'd try it out (finally).

As someone who uses lambdas often to select subsets of collections, when should I use LINQ and when should I use lambdas? There are questions like this one which show a 10-100x difference in performance one way or the other.

Community
  • 1
  • 1
ashes999
  • 9,925
  • 16
  • 73
  • 124

5 Answers5

5

LINQ evaluation is deferred. The expression for primes and numbers.Where(n => isOddAndNotDivisibleBy(n)) are identical to the compiler. In both cases, isOddAndNotDivisibleBy is never called until something evaluates a result of the expression. In this case, the ToArray between c and b forces the evaluation. If you added ToArray between a and b, you'd get similar times.

for comparison you could try:

var primes = (
    from n in numbers
    where isOddAndNotDivisibleBy(n)
    select n).ToArray();
Jimmy
  • 89,068
  • 17
  • 119
  • 137
  • This narrowed the performance to ~10% difference. But, it doesn't tell me which to use in which case, assuming somewhat similar performance "most of the time." – ashes999 Oct 24 '11 at 18:24
  • There is no difference at all -- the two versions are equivalent (they compile to the same IL). You use whichever one looks better to you. – Jimmy Oct 24 '11 at 18:27
  • The linked question with the 100x speedup made the same mistake you made the first time around -- they forgot to call ToArray(), ToList(), Count() etc. at the end, which meant that they query never had to execute. – Jimmy Oct 24 '11 at 18:30
  • If you see a performance difference, it is because some data is cached. If you change the order of the two, you will see an identical, but swapped performance difference – Squirrelsama Oct 24 '11 at 18:31
3

What you call “LINQ”, is actually called LINQ query syntax. And what you cal “anonymous lambda” is actually called LINQ method syntax. The important thing is that the expression:

from n in numbers
where isOddAndNotDivisibleBy(n)
select n

is actually transformed to this before compiling:

numbers.Where(n => isOddAndNotDivisibleBy(n))

This means that if you use the former or the latter directly, you will get the same IL code.

So the difference has to be somewhere else. And it's the ToArray() call. Where() is lazy. That means it does almost nothing, unless you actually iterate over the resulting sequence in one way or another. That means that just calling Where() is going to be nigh instantaneous. But if you call ToArray(), the collection is actually iterated and the results are computed immediately. That's why you see such a huge difference.

EDIT:

To the modified question: why use one syntax over the other? Primarily choose the one that is more readable.

There are some methods and overloads that you can't express using query syntax (First(), Aggregate(), Concat() Zip(), overloads that introduce index, …). But you can use one syntax for one part of the query and another for the rest.

There is also one powerful feature of query syntax that can't be easily expressed using method syntax: transparent identifiers, e.g. when using the let clause.

But there are no performance differences between the two syntaxes, at least when used correctly.

svick
  • 236,525
  • 50
  • 385
  • 514
  • LINQ method syntax? I think you mean dot notation, or method chain syntax. – Saeed Amiri Oct 24 '11 at 18:31
  • That's what MS calls it: http://msdn.microsoft.com/en-us/library/bb397947.aspx – svick Oct 24 '11 at 18:35
  • So Microsoft has problem because in http://msdn.microsoft.com/en-us/library/bb308959.aspx says it dot notation, also method syntax is meaningful in fact, because we have method chaining pattern (see http://en.wikipedia.org/wiki/Method_chaining) it's better to say method chaining (because linq implement it in dot notation:) not method syntax. – Saeed Amiri Oct 24 '11 at 18:40
1

Your tests aren't the same: You are calling ToArray() between b and c, which will allocate (and then reallocate, and then reallocate) memory after actually executing your query.

Between a and b, you just create a query that, when executed, will perform the calculation. Calling ToList(), ToArray(), or iterating the query via foreach loop will actually force it to be executed; it should take almost excatly the same amount of time, since it will be translated from query comprehension syntax into a series of extension method calls that match your second test.

Finally, never use DateTime.Now for timing; use StopWatch.

dlev
  • 48,024
  • 5
  • 125
  • 132
1

Because you didn't execute linq one just do primes .ToArray() and then compare them. in fact this is a deffered execution behavior of linq, it just creates query and didn't run it, til you execute it with some function like, foreach, ToList, ...

Also both of things you done is linq, because both are using some extension methods on IEnumerable in Enumerable class, just first one is query syntax and second one is Dot Notation syntax. see them in msdn linq.

svick
  • 236,525
  • 50
  • 385
  • 514
Saeed Amiri
  • 22,252
  • 5
  • 45
  • 83
0

Both of those cases are, indeed, identical LINQ queries, but with different syntactical sugar.

What do I mean by queries? A LINQ query, whether you create it with mySequence.Where(i => i > 5) or (from item in mySequence where item > 5), the only data that is stored is that which allows you to enumerate the sequence.

When you ToArray or ToList or ToDictionary or foreach, the sequence is then evaluated, which is why you have such a huge performance gap -- i.e. your first query is not evaluated. Ever.

Squirrelsama
  • 5,480
  • 4
  • 28
  • 38