Deferred Execution in LINQ

A LINQ Tutorial

As part of my on-going exploration of technologies related to programming Silverlight Doubler and Windows Phone, I’ve been exploring LINQ in some detail.

Today, I’d like to take a look at how LINQ queries are executed; specifically focusing on the delay in execution that makes LINQ so performant.

[Double click on image for full size]

To begin, divide your main page vertically into two equal columns, and add a ListBox to each column, as shown in the following Xaml,

<Grid
   x:Name="ContentPanel"
   Grid.Row="1"
   Margin="12,0,12,0">
   <Grid.ColumnDefinitions>
      <ColumnDefinition
         Width="1*" />
      <ColumnDefinition
         Width="1*" />
   </Grid.ColumnDefinitions>
   <ListBox
      Name="DeferredLB"
      Grid.Column="0"
      Margin="10"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Stretch" />

   <ListBox
      Name="NotDeferredLB"
      Grid.Column="1"
      Margin="10"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Stretch" />
</Grid>

To demonstrate that LINQ uses deferred execution, we’ll set up a query that relies on a method call.  Inside the method call, we can add to the ListBox so that we can see which method is running at any given moment.

 public MainPage( )
 {
    InitializeComponent( );
    int[] primes = { 1, 2, 3, 5, 7, 11, 13, 17, 19 };

    var query =
    from prime in primes
    select Doubler( prime, DeferredLB );

    foreach ( var n in query )
       DeferredLB.Items.Add( n );
 }

 private static int Doubler( int n, ListBox lb )
 {
    lb.Items.Add( "Doubling " + n );
    n *= 2;
    return n;
 }

When you run this application, you see that control bounces back and forth from the query in Main to the Doubler method as each item is yielded in the enumerator that is implicitly called by the foreach loop.  The query is not executed until needed and if you were to cut off the query half way through then the remaining values would never load into memory.

To nail this down, let’s force the query to be executed all at once.  To do this, all we do is to convert the query to a list. This forces the query to execute in full (to populate the list) and then we can iterate through that list all in one go.  We’ll populate the right hand list box with the results of that approach:

 public MainPage( )
 {
    InitializeComponent( );
    int[] primes = { 1, 2, 3, 5, 7, 11, 13, 17, 19 };

    var query =
    from prime in primes
    select Doubler( prime, DeferredLB );

    foreach ( var n in query )
       DeferredLB.Items.Add( n );

    query =
    from prime in primes
    select Doubler( prime, NotDeferredLB );

    foreach ( var n in query.ToList( ) )
       NotDeferredLB.Items.Add( n );
 }

The result is shown in the image at the top of this posting.

Note that we use an array and the compiler optimizes enumeration of arrays, but that does not affect the point made in this discussion.

Share

About Jesse Liberty

Jesse Liberty is an independent consultant and programmer with three decades of experience writing and delivering software projects. He is the author of 2 dozen books and multiple Pluralsight courses, and has been a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Xamarin Certified Mobile Developer and a Xamarin MVP, Microsoft MVP and Telerik MVP.
This entry was posted in Data, Essentials, Linq, Mini-Tutorial, WindowsPhone and tagged . Bookmark the permalink.

4 Responses to Deferred Execution in LINQ

  1. testdomain says:

    you are in point of fact a just right webmaster. The site loading pace is incredible. It seems that you are doing any unique trick. In addition, The contents are masterpiece. you have performed a fantastic job on this matter!

  2. Abhishek Gahlout says:

    Nice article with very simple approcah to make understand the tricky concept!!!!

  3. Thank you very much about your instruction when I have come to your web

  4. Arash says:

    Usually not a good idea to do this for the following reason: if you have some complex creation of a list, and you do it in a deferred manner (i.e. you are using operators like Union and Where), the creation of that list will happen on the UI thread.

    It’s better to just do all work on a background thread, and call “ToList” to ensure the list is actually created on that background thread, before returning that list to the UI.

Leave a Reply

Your email address will not be published.