Reputation: 654
If you search is Linq faster the Foreach the answer always is no a foreach is. I also found another stackoverflow question where the question asker had not done a "warmup" so I've included a "warmup" in my code.
My code example for some reason did not act as I expected. I'm thinking what I've done is make the no linq path loop twice--once the first time and once at the sum. Where as the linq example loops only once at the end when it does a sum. What do you think? Is my test flawed or is this a scenario where linq actually buys us a good performance increase?
public class NumberObject { public Int32 Number { get; set; } }
public IEnumerable<NumberObject> GetNumbersWithoutLambda()
{
IEnumerable<Int32> numberRange = Enumerable.Range(0,10);
List<NumberObject> numberList = new List<NumberObject>();
foreach (Int32 item in numberRange)
{
numberList.Add(new NumberObject() { Number = item });
}
return numberList;
}
public IEnumerable<NumberObject> GetNumbersWithLambda()
{
IEnumerable<Int32> numberRange = Enumerable.Range(0, 10);
IEnumerable<NumberObject> numbers = numberRange.
Select(number => new NumberObject() { Number = number });
return numbers;
}
private void runGetNumbers(Func<IEnumerable<NumberObject>> getNumbersFunction, Int32 numberOfTimesToRun)
{
for (int i = 0; i < numberOfTimesToRun; i++)
{
IEnumerable<NumberObject> numbers = getNumbersFunction();
//numbers.Count();
numbers.Sum(item => item.Number);
//numbers.Average(item => item.Number);
}
}
[TestMethod]
public void record_speed_of_GetNumbers()
{
Int32 numberOfTimes = 10000000;
Console.WriteLine("Doing warmup... " +
TimeMethod(() => runGetNumbers(GetNumbersWithLambda, numberOfTimes)));
Console.WriteLine("GetNumbersWithoutLambda: " +
TimeMethod(() => runGetNumbers(GetNumbersWithoutLambda, numberOfTimes)) + " milliseconds");
Console.WriteLine("GetNumbersWithLambda: " +
TimeMethod(() => runGetNumbers(GetNumbersWithLambda, numberOfTimes)) + " milliseconds");
}
static long TimeMethod(Action methodToTime)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
methodToTime();
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
Below is the output from the test:
Doing warmup... 7560
GetNumbersWithoutLambda: 14779 milliseconds
GetNumbersWithLambda: 7626 milliseconds
The interesting this is that the "warmup" run actually does not seem to apply in this case.
Upvotes: 3
Views: 12004
Reputation: 1512
Not exactly. It up to what you have done with Linq
If you just use foreach
to iterate and modified item in collection without creating new collection. Then Linq is slower in general
But most people tend to create collection just for iteration in their long logic. That allocate memory and that make it slower than using Linq, because Linq does not create real collection, it just remember the iteration logic to execute when foreach
Overusing Linq sometimes slow down if it not necessary. Because using Linq create delegate object and cause stack allocation
Upvotes: 0
Reputation: 942338
You are comparing apples and oranges, Linq doesn't use a List<> like your "non-lambda" version does. That list doesn't come for free.
You'll need to write it like this:
public IEnumerable<NumberObject> GetNumbersWithoutLambda() {
IEnumerable<Int32> numberRange = Enumerable.Range(0, 10);
foreach (Int32 item in numberRange) {
yield return new NumberObject() { Number = item };
}
}
It now takes the same amount of time. And yes, Linq uses iterators as well.
That however doesn't hold a candle to the unlinquified version, it is five times faster:
static int sum; // Ensures summing doesn't get optimized away
private void runGetNumbers2(Int32 numberOfTimesToRun) {
for (int i = 0; i < numberOfTimesToRun; i++) {
foreach (var number in Enumerable.Range(0, 10)) {
sum += number;
}
}
}
Make it another three times faster yet by dropping Enumerable.Range:
for (int i = 0; i < numberOfTimesToRun; i++) {
for (int j = 0; j < 10; ++j) {
sum += j;
}
}
Which demonstrates that the state machine that iterators use isn't for free either. Basic premise here is that simple code is fast.
Upvotes: 7
Reputation: 1843
The difference is that even though a List implements IEnumerable, it must be fully populated before the method can return where the Linq method only needs to construct the expression tree before returning.
Consider and time the following:
public IEnumerable<NumberObject> GetNumbersWithLambdaToList()
{
IEnumerable<Int32> numberRange = Enumerable.Range(0, 10);
IEnumerable<NumberObject> numbers = numberRange.
Select(number => new NumberObject() { Number = number });
return numbers.ToList();
}
public IEnumerable<NumberObject> GetNumbersWithYield()
{
IEnumerable<Int32> numberRange = Enumerable.Range(0,10);
foreach (Int32 item in numberRange)
{
yield return (new NumberObject() { Number = item });
}
}
On my machine:
GetNumbersWithoutLambda: 9631 milliseconds
GetNumbersWithLambda: 7285 milliseconds
GetNumbersWithLambdaToList: 12998 milliseconds
GetNumbersWithYield: 9236 milliseconds
Upvotes: 5
Reputation: 61379
LINQ will usually be faster when it can take advantage of deferred execution; as it does here.
As you suspected; foreach
fully enumerates the collection in your code. Select
just builds a query to do that enumeration.
Then when you call Sum
, it enumerates the previously generated collection. We have a total of 2 enumerations for foreach
and just one for Select
, so it is faster (by a factor of 2!)
There are other examples; Take
, and First
will stop execution early (a foreach
can stop early, but most people don't code it that way).
Basically, use foreach
when you actually need to enumerate the whole collection for what you are doing, or when you want to enumerate (consume) a LINQ query. Use LINQ when you are running queries and operations where deferred execution will get you a performance benefit. When that query returns a collection, use foreach
to iterate over it.
Upvotes: 13