Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is LINQ faster in this example

I wrote the following to test the performance of using foreach vs LINQ:

private class Widget
{
    public string Name { get; set; }
}

static void Main(string[] args)
{
    List<Widget> widgets = new List<Widget>();
    int found = 0;

    for (int i = 0; i <= 500000 - 1; i++)
        widgets.Add(new Widget() { Name = Guid.NewGuid().ToString() });

    DateTime starttime = DateTime.Now;

    foreach (Widget w in widgets)
    {
        if (w.Name.StartsWith("4"))
            found += 1;
    }

    Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");

    starttime = DateTime.Now;
    found = widgets.Where(a => a.Name.StartsWith("4")).Count();

    Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");

    Console.ReadLine();
}

I get something like following output:

31160 - 116ms
31160 - 95 ms

In every run, LINQ outperforms foreach by around 20%. It was my understanding that the LINQ extension methods used standard c# under the covers.

So why is LINQ faster in this case?

EDIT:

So I changed my code to use stopwatch instead of datetime and still get the same results. If I run the LINQ query first then my results show LINQ to be about 20% slower then foreach. This has to be some sort of JIT warmnup issue. My question is how do I compensate for JIT warmup in my test case?

like image 579
Coltech Avatar asked Jun 17 '13 12:06

Coltech


People also ask

Why is LINQ faster?

If a new method is thought up that's incredibly fast, the people at Microsoft can implement it without even telling you and your code would be a lot faster. More importantly though, LINQ is just much easier to read. That should be enough reason.

Is LINQ fast or slow?

LINQ is absolutely 100% slower You are going to essentially "stall-out" if you are performing any complex queries, joins etc...

Is LINQ faster than foreach loop?

LINQ syntax is typically less efficient than a foreach loop. It's good to be aware of any performance tradeoff that might occur when you use LINQ to improve the readability of your code.


1 Answers

It's because you do not have a warmup. If you reverse your cases you will get excatly the opposit result:

31272 - 110ms
31272 - 80 ms

Start adding a warmup and use a stopwatch for better timing.

Running the test with warmup:

        //WARM UP:
        widgets.Where(a => a.Name.StartsWith("4")).Count();

        foreach (Widget w in widgets)
        {
            if (w.Name.StartsWith("4"))
                found += 1;
        }

        //RUN Test
        Stopwatch stopwatch1 = new Stopwatch();
        stopwatch1.Start();

        found = widgets.Where(a => a.Name.StartsWith("4")).Count();
        stopwatch1.Stop();

        Console.WriteLine(found + " - " + stopwatch1.Elapsed);

        found = 0;
        Stopwatch stopwatch2 = new Stopwatch();
        stopwatch2.Start();

        foreach (Widget w in widgets)
        {
            if (w.Name.StartsWith("4"))
                found += 1;
        }
        stopwatch2.Stop();

        Console.WriteLine(found + " - " + stopwatch2.Elapsed);

result:

31039 - 00:00:00.0783508
31039 - 00:00:00.0766299
like image 118
Peter Avatar answered Oct 11 '22 11:10

Peter