Francisco Aguilera
Francisco Aguilera

Reputation: 3482

LINQ vs foreach vs for performance test results

Could somebody explain these results? I know there are duplicate questions, but I have yet to find a single question that came to the same conclusion as my results :o

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SpeedTest
{
    class Person
    {    
        public Person(string name)
        {
            this.Name = name;
        }

        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var people = new List<Person>();
            AddTwins("FRANCISCO", people);
            var stopwatch = new Stopwatch();

            string name = "OCSICNARF";

            long linqTime = 0L;
            long foreachTime = 0L;
            long forTime = 0L;

            stopwatch.Start();
            Person person0;
            var result = from person in people
                         where person.Name == name
                         select person;
            person0 = result.First();
            linqTime = stopwatch.ElapsedMilliseconds;
            stopwatch.Restart();
            Person person1;
            foreach (Person p in people)
            {
                if (p.Name == name)
                {
                    person1 = p;
                    break;
                }
            }
            foreachTime = stopwatch.ElapsedMilliseconds;
            stopwatch.Restart();
            Person person2;
            for (int i = 0; i < people.Count; i++)
            {
                if (people[i].Name == name)
                {
                    person2 = people[i];
                    break;
                }
            }
            forTime = stopwatch.ElapsedMilliseconds;
            stopwatch.Stop();

            Console.WriteLine(string.Format("LINQ took {0}ms", linqTime));
            Console.WriteLine(string.Format("FOREACH took {0}ms", foreachTime));
            Console.WriteLine(string.Format("FOR took {0}ms", forTime));
        }

        static void AddTwins(string name, List<Person> people)
        {
            AddTwins(people, name, "");
        }

        private static void AddTwins(List<Person> people, string choices, string chosen)
        {
            if (choices.Length == 0)
            {
                people.Add(new Person(chosen));
            }
            else
            {
                for (int i = 0; i < choices.Length; i++)
                {
                    // choose
                    char c = choices[i];
                    string choose1 = choices.Substring(0, i);
                    string choose2 = choices.Substring(i + 1);
                    choices = choose1 + choose2;

                    // explore
                    AddTwins(people, choices, chosen + c);

                    // Unchoose
                    string unchoose1 = choices.Substring(0, i);
                    string unchoose2 = choices.Substring(i);
                    choices = unchoose1 + c + unchoose2;
                }
            }
        }
    }
}

enter image description here

Upvotes: 9

Views: 22668

Answers (3)

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101681

You never execute the LINQ query, you just create it. You should use ToList or ToArray method to force an iteration, probably you won't get a different result because LINQ uses a foreach loop as well.

Edit: LINQ takes a little bit more time because you are iterating over all of the items. But in your other two loops you are breaking the loop as soon as you find a match. Try using FirstOrDefault instead of Where and you should get the same (or similar) result.

people.FirstOrDefault(p => p.Name == name);

Upvotes: 18

phoog
phoog

Reputation: 43046

It is apparently significant that Sum has to store a boxed instance of the list enumerator on the heap, and use that heap object to iterate the list. The inline foreach and the for loop both avoid this; the former because List's public GetEnumerator method returns a value type. If you store a reference to people in an IEnumerable<Person> variable, the foreach loop takes a little longer to get to its result.

Also, linq has to create objects for the where iterator and the delegate passed to it, and it does more null checks so it can throw informative exceptions if any of the arguments is null. That could account for the rest of the additional time required for the linq code.

Upvotes: 0

John Gardner
John Gardner

Reputation: 25116

the linq one is taking no time because the query is never actually evaluated.

Linq is lazy for most operations, it won't actually do anything until someone starts enumerating the results.

if you added

result.Count(); // add this line, query will be evaluated
linqTime = stopwatch.ElapsedMilliseconds;
stopwatch.Restart();

then i'm pretty sure you'd have a non-zero result for linq.

Upvotes: 1

Related Questions