Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the LINQ to objects 'where' clause doing behind the scenes?

I've just replaced this piece of code:

foreach( var source in m_sources )
{
    if( !source.IsExhausted )
    {
        ....
    }
}

with this one:

foreach( var source in m_sources.Where( src => !src.IsExhausted ) )
{
   ...
}

Now the code looks better (to me) but I'm wondering what's really happening here. I'm concerned about performance in this case, and it'd be bad news if applying this filter would mean that some kind of compiler magic would take place.

Are the two pieces of code doing basically the 'same' thing? Are temporary containers created to do the filtering then passing them to my foreach?

Any help on the subject will be pretty much appreciated. Thanks.

like image 377
Trap Avatar asked Mar 19 '09 22:03

Trap


2 Answers

The yield return keyword and lambdas do involve the creation of hidden classes at compile time and the allocation of extra objects at runtime, and if your background is in C or C++ then it's only natural to be concerned about performance.

Natural, but wrong!

I tried measuring the overhead for lambdas with closure over local variables, and found it to be so incredibly small (a matter of nanoseconds) that it would be of no significance in almost all applications.

like image 179
Daniel Earwicker Avatar answered Oct 27 '22 11:10

Daniel Earwicker


It depends on the type if m_sources.

If it is a Data Context from LINQ to SQL or Entity Framework the argument you pass is compiled as an instance of Expression and parsed to create SQL (with the help of the data model). There are some real costs in this process, but likely (in most cases) to be dominated by the round trip to the database.

If it is IEnumerable then Where is pretty much implemented as:

public static IEnumnerable<T> Where(this IEnumerable<T> input, Func<T, bool> predicate) {
  foreach (var v in input) {
    if (predicate(v)) {
      yield return v;
    }
  }
}

Which is pretty efficient and performs lazily (so if you break out of your loop early the predicate will not be applied to the whole collection).

like image 36
Richard Avatar answered Oct 27 '22 09:10

Richard