简体   繁体   English

LINQ 语句是否比“foreach”循环更快?

[英]Is a LINQ statement faster than a 'foreach' loop?

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 render 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?我目前正在使用foreach循环,但想知道使用 LINQ 是否可以提高性能?

Why should LINQ be faster?为什么 LINQ 应该更快? It also uses loops internally.它还在内部使用循环。

Most of the times, LINQ will be a bit slower because it introduces overhead.大多数情况下,LINQ 会慢一点,因为它引入了开销。 Do not use LINQ if you care much about performance.如果您非常关心性能,请不要使用 LINQ。 Use LINQ because you want shorter better readable and maintainable code.使用 LINQ 是因为您想要更短、更易读和可维护的代码。

LINQ-to-Objects generally is going to add some marginal overheads (multiple iterators, etc). LINQ-to-Objects通常会增加一些边际开销(多个迭代器等)。 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.使用其他 LINQ 提供程序(如 LINQ-to-SQL),那么由于查询可以在服务器上进行过滤,它应该比平面foreach好得多,但是很可能无论如何您都不会进行全面的"select * from foo" ,所以这不一定是公平的比较。

Re PLINQ;重新 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.并行性可能会减少经过的时间,但由于线程管理等的开销,总 CPU 时间通常会增加一点。

I think LINQ is better to use over a foreach loop, because it gives you much cleaner and easy-to-understand code. 我认为LINQ最好在foreach循环中使用,因为它可以使您的代码更加简洁明了。 But LINQ is slower than foreach . 但是LINQ比foreach慢。 To get more, go through the article LINQ vs FOREACH vs FOR Loop Performance . 要获得更多信息,请阅读文章LINQ vs FOREACH vs FOR Loop Performance

LINQ is slower now, but it might get faster at some point. LINQ 现在变慢了,但在某些时候它可能会变得更快。 The good thing about LINQ is that you don't have to care about how it works. LINQ 的好处是你不必关心它是如何工作的。 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.如果想出一种新方法,而且速度非常快,Microsoft 的人员甚至可以在不告诉您的情况下实现它,并且您的代码会快得多。

More importantly though, LINQ is just much easier to read.更重要的是,LINQ 更容易阅读。 That should be enough reason.这应该是足够的理由。

It should probably be noted that the for loop is faster than the foreach .可能应该注意到for循环比foreach快。 So for the original post, if you are worried about performance on a critical component like a renderer, use a for loop.因此,对于原始帖子,如果您担心渲染器等关键组件的性能,请使用for循环。

Reference: In .NET, which loop runs faster, 'for' or 'foreach'?参考: 在 .NET 中,哪个循环运行得更快,“for”还是“foreach”?

You might get a performance boost if you use parallel LINQ for multi cores.如果您对多核使用并行 LINQ,您可能会获得性能提升。 See Parallel LINQ (PLINQ) (MSDN).请参阅并行 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.在 Intel(R) Core(TM) i3-2328M CPU @ 2.20GHz, 2200 Mhz, 2 Core(s) with 8GB ram 上使用 .NET Framework 4.5.2,运行 Microsoft Windows 7 Ultimate。

It looks like LINQ might be faster than for each loop.看起来 LINQ 可能比每个循环都快。 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. LINQ 在那里也更快。

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 (eg linq .Except()). Linq 使某些事情很容易做,如果你自己实现它们,你可能会绊倒(例如 linq .Except())。 This particularly applies to PLinq, and especially to parallel aggregation as implemented by PLinq.这尤其适用于 PLinq,尤其适用于 PLinq 实现的并行聚合。

In general, for identical code, linq will be slower, because of the overhead of delegate invocation.一般来说,对于相同的代码,由于委托调用的开销,linq 会更慢。

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).您使用 for 循环来访问每个元素(而不是 foreach 或 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.注意:在进行基准测试时,请大家记住——如果连续两次测试使用相同的数组/列表,CPU 缓存会使第二次测试更快。 * *

The answers above may have been right in 2010, ... 15 . 以上答案在2010年可能是正确的,... 15。 But I think that's not the case anymore: 但我认为情况已不再如此:

When I run this comparison code. 当我运行此比较代码时。 I obtain the following results: 我得到以下结果:

    var time = Stopwatch.StartNew();
    var loops = 10000000;
    time.Start();
    var arr = new string[loops];
    for (var i = 0; i < loops; i++)
    {
        arr[i] = "Loop" + i;
    }
    time.Stop();
    Console.WriteLine("TIME: " + time.ElapsedMilliseconds + "ms");

I obtained the following result 我得到了以下结果

TIME: 6794ms 时间:6794ms

But when I switched to linq : 但是当我切换到linq时

    var time = Stopwatch.StartNew();
    var loops = 10000000;
    time.Start();
    var strList = Enumerable.Range(0, loops).Select(i => "Loop" + i).ToList();
    time.Stop();
    Console.WriteLine("TIME: " + time.ElapsedMilliseconds + "ms");

TIME: 2ms 时间:2ms

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM