3

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.

Community
  • 1
  • 1
Simon The Cat
  • 604
  • 1
  • 8
  • 22
  • The question "is LINQ faster than a foreach" is wrong. You cannot compare both, a foreach can execute a LINQ query. – Tim Schmelter Nov 07 '14 at 21:26
  • 1
    Moreover, both code snippets don't really do the same thing, as stated in Bradley's answer. – Patrice Gahide Nov 07 '14 at 21:29
  • 3
    The question is really "if I copy collection to list it is twice as slow if I don't, why doing twice as much work is twice slower"... You can use foreach just fine in both cases to get exactly the same results. – Alexei Levenkov Nov 07 '14 at 21:29
  • 1
    Your code is comparing apples to oranges. If I write a LINQ expression that takes the first item from a list, it'll be faster than a `foreach` loop running a complex iteration and checks on all items of a list. A well-written `foreach` loop has less overhead than a LINQ query but a LINQ query may be easier to put together than a well-written, efficient foreach loop. – xxbbcc Nov 07 '14 at 21:30
  • @PatriceGahide The results are the same when called from `runGetNumbers`. The difference is the intermediate work to get the collection(s) to that point. – user2864740 Nov 07 '14 at 21:33
  • Come to think of it - to make both branches do the same thing use "LINQ" `.ToList()` call in the second case to get comparable code/timing. – Alexei Levenkov Nov 07 '14 at 21:33
  • 1
    Some other perspectives to try would be to call `.ToList()` on your GetMembersWithLambda method, or to create a [generator function](http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx) of your `foreach` loop. – psaxton Nov 07 '14 at 21:33
  • @xxbbcc: a LINQ query can also be more efficient (using set methods like `Join`, `GroupBy`, `Except`, `Intersect`,...). So this question is comparing apples and oranges. – Tim Schmelter Nov 07 '14 at 21:34
  • @TimSchmelter I didn't mean to say the opposite. A complex LINQ query can be rewritten as an efficient `foreach` loop but it takes quite a bit of effort to do so and it's easy to get it wrong. – xxbbcc Nov 07 '14 at 21:35
  • @TimSchmelter there is absolutely nothing magical about LINQ - it just set of well thought out functions that makes code easier to write/reason about. Indeed it is often way more efficient to read/write than equivalent lower level manual iteration/collections/hastables, but the post seem to take different meaning of "efficient" as in "faster" rather than "easier to understand". – Alexei Levenkov Nov 07 '14 at 21:38
  • @AlexeiLevenkov: i haven't said that LINQ is magic. But many people reduce it's purpose to readability. Imo, LINQ can not only reduce complexity and increase readability but also efficiency. It's _easier_ to write high performance code when it matters and when it's getting complex with LINQ than with plain (nested) loops. – Tim Schmelter Nov 07 '14 at 21:49

4 Answers4

13

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.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • @user2864740 How so? Thats the difference here. LINQ only enumerates once. I would be happy to use different wording if you have a suggestion. – BradleyDotNET Nov 07 '14 at 21:26
  • 1
    "foreach actually builds a new list "??? Either you forgot to clearly specify context OR your trying to confuse people... I hope first... – Alexei Levenkov Nov 07 '14 at 21:27
  • The opening is better (and I won't raise a fuss about it) after changing "always"; the remainder of the answer is the meat and potatoes. There are some subtleties with re-enumerating Enumerables and different query providers as well which sometimes comes up, which was the underlying motivation of my initial comment. – user2864740 Nov 07 '14 at 21:27
  • @AlexeiLevenkov Sorry, it was doing that in his code. That is not true of `foreach` in *general* of course. – BradleyDotNET Nov 07 '14 at 21:28
  • @AlexeiLevenkov I just removed that piece; it wasn't important anyways. – BradleyDotNET Nov 07 '14 at 21:28
  • 1
    You could add: use a `foreach` if you want to enumerate your LINQ query. So the `foreach` consumes it, both play well together since they have different purposes. – Tim Schmelter Nov 07 '14 at 21:29
7

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.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • That's not really meaningful though. It's not even clear what you're benchmarking here. The `yield` construct? Lambdas? – GregRos Nov 07 '14 at 21:51
  • Some programmers think that x15 faster code is meaningful. Hope that downvote made you feel better. – Hans Passant Nov 07 '14 at 23:28
  • The yield construct actually [wasn't the same speed](http://stackoverflow.com/questions/26810267/is-this-really-a-case-when-linq-is-faster-than-a-foreach/26810478#26810478) as the Linq `.Select`, which surprised me. You never know until you profile. :) – psaxton Nov 08 '14 at 01:04
5

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
psaxton
  • 1,693
  • 19
  • 24
0

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

Thaina Yu
  • 1,372
  • 2
  • 16
  • 27