In your example, you say "First of all, the Enumerable.Range method will produce a sequence of integers, from 0 to 2,147,483,647." Are 2 billion integers actually created in memory? My fear about LINQ has always been around performance. Is it smart enough to only create the 10 integers actually desired?
Great question! Let's look at what is going on in more detail. Here is the code that he is referring to:
static void Main(string[] args)
{
var smallNumbers = Enumerable.Range(0, int.MaxValue).Where(n => n < 10);
foreach (int i in smallNumbers)
{
Console.WriteLine(i);
}
}
Both the Range and the Where method return an IEnumerable<int> and use deferred execution. This means that they are just returning a enumerator that knows how to traverse the sequence of integers from 0 to 2,147,483,647. It is not returning that entire set of numbers. The query represented by "Enumerable.Range(0, int.MaxValue).Where(n => n < 10)" is not executed until smallNumbers is enumerated. In this specific example, that enumeration is done by the foreach statement.
Therefore, two billion integers are not created in memory at once. They are created one at a time during the foreach statement. But it will check all two billion plus values, because that is the defined behavior of the Where method - to check each member of the range to see if the predicate n < 10 is true. As mentioned in my previous post, a better way to implement this specific code example is to use the TakeWhile method instead of the Where method. The TakeWhile method tests each number in the range and yields the number if n < 10, but enumeration stops once n >= 10 (or if there are no more numbers in the range).
Try running the above code, and then replace "Where" with "TakeWhile" and run it again. The "TakeWhile" version should run much faster.
Great question! Let's look at what is going on in more detail. Here is the code that he is referring to:
static void Main(string[] args)
{
var smallNumbers = Enumerable.Range(0, int.MaxValue).Where(n => n < 10);
foreach (int i in smallNumbers)
{
Console.WriteLine(i);
}
}
Both the Range and the Where method return an IEnumerable<int> and use deferred execution. This means that they are just returning a enumerator that knows how to traverse the sequence of integers from 0 to 2,147,483,647. It is not returning that entire set of numbers. The query represented by "Enumerable.Range(0, int.MaxValue).Where(n => n < 10)" is not executed until smallNumbers is enumerated. In this specific example, that enumeration is done by the foreach statement.
Therefore, two billion integers are not created in memory at once. They are created one at a time during the foreach statement. But it will check all two billion plus values, because that is the defined behavior of the Where method - to check each member of the range to see if the predicate n < 10 is true. As mentioned in my previous post, a better way to implement this specific code example is to use the TakeWhile method instead of the Where method. The TakeWhile method tests each number in the range and yields the number if n < 10, but enumeration stops once n >= 10 (or if there are no more numbers in the range).
Try running the above code, and then replace "Where" with "TakeWhile" and run it again. The "TakeWhile" version should run much faster.
0 comments:
Post a Comment