开发者

Is a LINQ statement faster than a 'foreach' loop?

开发者 https://www.devze.com 2023-01-05 04:02 出处:网络
I am writing a Mesh Rendering manager and thought it would be a good idea to group all of the meshes which use the same shader and then re开发者_如何学Gonder these while I\'m in that shader pass.

I am writing a Mesh Rendering manager and thought it would be a good idea to group all of the meshes which use the same shader and then re开发者_如何学Gonder these while I'm in that shader pass.

I am currently using a foreach loop, but wondered if utilising LINQ might give me a performance increase?


Why should LINQ be faster? It also uses loops internally.

Most of the times, LINQ will be a bit slower because it introduces overhead. Do not use LINQ if you care much about performance. Use LINQ because you want shorter better readable and maintainable code.


LINQ-to-Objects generally is going to add some marginal overheads (multiple iterators, etc). It still has to do the loops, and has delegate invokes, and will generally have to do some extra dereferencing to get at captured variables etc. In most code this will be virtually undetectable, and more than afforded by the simpler to understand code.

With other LINQ providers like LINQ-to-SQL, then since the query can filter at the server it should be much better than a flat foreach, but most likely you wouldn't have done a blanket "select * from foo" anyway, so that isn't necessarily a fair comparison.

Re PLINQ; parallelism may reduce the elapsed time, but the total CPU time will usually increase a little due to the overheads of thread management etc.


LINQ is slower now, but it might get faster at some point. The good thing about LINQ is that you don't have to care about how it works. 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.


It should probably be noted that the for loop is faster than the foreach. So for the original post, if you are worried about performance on a critical component like a renderer, use a for loop.

Reference: In .NET, which loop runs faster, 'for' or 'foreach'?


You might get a performance boost if you use parallel LINQ for multi cores. See Parallel LINQ (PLINQ) (MSDN).


I was interested in this question, so I did a test just now. Using .NET Framework 4.5.2 on an Intel(R) Core(TM) i3-2328M CPU @ 2.20GHz, 2200 Mhz, 2 Core(s) with 8GB ram running Microsoft Windows 7 Ultimate.

It looks like LINQ might be faster than for each loop. Here are the results I got:

Exists = True
Time   = 174
Exists = True
Time   = 149

It would be interesting if some of you could copy & paste this code in a console app and test as well. Before testing with an object (Employee) I tried the same test with integers. LINQ was faster there as well.

public class Program
{
    public class Employee
    {
        public int id;
        public string name;
        public string lastname;
        public DateTime dateOfBirth;

        public Employee(int id,string name,string lastname,DateTime dateOfBirth)
        {
            this.id = id;
            this.name = name;
            this.lastname = lastname;
            this.dateOfBirth = dateOfBirth;

        }
    }

    public static void Main() => StartObjTest();

    #region object test

    public static void StartObjTest()
    {
        List<Employee> items = new List<Employee>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(new Employee(i,"name" + i,"lastname" + i,DateTime.Today));
        }

        Test3(items, items.Count-100);
        Test4(items, items.Count - 100);

        Console.Read();
    }


    public static void Test3(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item.id == idToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test4(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Exists(e => e.id == idToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion


    #region int test
    public static void StartIntTest()
    {
        List<int> items = new List<int>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(i);
        }

        Test1(items, -100);
        Test2(items, -100);

        Console.Read();
    }

    public static void Test1(List<int> items,int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item == itemToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test2(List<int> items, int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Contains(itemToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion

}


This is actually quite a complex question. Linq makes certain things very easy to do, that if you implement them yourself, you might stumble over (e.g. linq .Except()). This particularly applies to PLinq, and especially to parallel aggregation as implemented by PLinq.

In general, for identical code, linq will be slower, because of the overhead of delegate invocation.

If, however, you are processing a large array of data, and applying relatively simple calculations to the elements, you will get a huge performance increase if:

  1. You use an array to store the data.
  2. You use a for loop to access each element (as opposed to foreach or linq).

    • Note: When benchmarking, please everyone remember - if you use the same array/list for two consecutive tests, the CPU cache will make the second one faster. *


Coming in .NET core 7 are some significant updates to LINQ performance of .Min .Max, .Average and .Sum Reference: https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/#linq

Here is a benchmark from the post.

Is a LINQ statement faster than a 'foreach' loop?

If you compare to a ForEach loop, than it becomes apparent that in .NET 6 the ForEach loop was faster and in .NET 7 the LINQ methods:

Is a LINQ statement faster than a 'foreach' loop?

this was the code of the benchmark using BenchmarkDotNet

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

public class Program
{
    public static void Main()
    {
        BenchmarkRunner.Run<ForEachVsLinq>();
    }
}

[SimpleJob(RuntimeMoniker.Net60)]
[SimpleJob(RuntimeMoniker.Net70)]
[MemoryDiagnoser(false)]
public class ForEachVsLinq
{
    private int[] _intArray;

    [GlobalSetup]
    public void Setup()
    {
        var random = new Random();
        var randomItems = Enumerable.Range(0, 500).Select(_ => random.Next(999));
        this._intArray = randomItems.ToArray();
    }

    [Benchmark]
    public void ForEachMin()
    {
        var min = int.MaxValue;
        foreach (var i in this._intArray)
        {
            if ( i < min)
                min = i;
        }
        Console.WriteLine(min);
    }

    [Benchmark]
    public void Min()
    {
        var min = this._intArray.Min();
        Console.WriteLine(min);
    }

    [Benchmark]
    public void ForEachMax()
    {
        var max = 0;
        foreach (var i in this._intArray)
        {
            if (i > max)
                max = i;
        }
        Console.WriteLine(max);
    }

    [Benchmark]
    public void Max()
    {
        var max = this._intArray.Max();
        Console.WriteLine(max);
    }


    [Benchmark]
    public void ForEachSum()
    {
        var sum = 0;
        foreach (var i in this._intArray)
        {
            sum += i;
        }
        Console.WriteLine(sum);
    }

    [Benchmark]
    public void Sum()
    {
        var sum = this._intArray.Sum();
        Console.WriteLine(sum);
    }
}

In .NET Core 6 and earlier versions the mentioned methods are slower than doing your own foreach loop and finding the min, max value, average or summarizing the objects in the array.

But in .NET Core 7, the performance increase makes these buildin LINQ methods actually a lot faster. Nick Chapsas shows this in a benchmark video on YouTupe

So if you want to calculate the sum, min, max or average value, you should use the LINQ methods instead of a foreach loop from .NET Core 7 onwards (at least, from a performance point of view)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号