【问题标题】:Is a LINQ statement faster than a 'foreach' loop?LINQ 语句是否比“foreach”循环快?
【发布时间】:2011-03-10 12:31:49
【问题描述】:

我正在编写一个网格渲染管理器,并认为将所有使用相同着色器的网格分组,然后在我处于该着色器通道时渲染它们是个好主意。

我目前正在使用foreach 循环,但想知道使用 LINQ 是否可以提高性能?

【问题讨论】:

标签: c# performance linq foreach


【解决方案1】:

为什么 LINQ 应该更快?它还在内部使用循环。

大多数时候,LINQ 会有点慢,因为它会引入开销。如果您非常关心性能,请不要使用 LINQ。使用 LINQ 是因为您想要更短、更易读、更易于维护的代码。

【讨论】:

  • 所以您的经验是 LINQ 速度更快,并且使代码更难阅读和维护?请解释一下。
  • 我认为你倒退了。他说LINQ更慢。这是由于开销过大。他还说 LINQ 更易于阅读和维护。
  • 对不起。与此同时,我们在很多方面比较了 linq 和 for 或 foreach 的性能,大多数时候 linq 更快。
  • 老实说,在我看来,foreach 循环比它的 LINQ 方法更具可读性。我使用 LINQ 是因为它很酷 :)
  • 是的,但在某些情况下 LINQ 确实可以提高可读性,所以忘记我的无脑评论
【解决方案2】:

LINQ-to-Objects 一般会增加一些边际开销(多个迭代器等)。它仍然必须执行循环,and 有委托调用,and 通常必须做一些额外的取消引用才能获取捕获的变量等。在大多数代码中,这实际上是无法检测到,并且超过更易于理解的代码所提供的功能。

使用 LINQ-to-SQL 等其他 LINQ 提供程序,由于查询可以在服务器上进行过滤,它应该更好 比平面 foreach,但很可能你不会有做了一个毯子"select * from foo"无论如何,所以这不是必然一个公平的比较。

重新 PLINQ;并行性可能会减少经过时间,但由于线程管理等开销,总 CPU 时间通常会增加一点。

【讨论】:

  • 在另一个答案中,您提到 not 在内存集合上使用 LINQ - 例如List<Foo>;相反,我应该在这些集合上使用 foreach 块。在这些情况下使用foreach 的建议确实有意义。我的担忧:我应该只用foreachif 替换 LINQ 查询吗?我检测到性能问题?展望未来,我将首先考虑foreach
【解决方案3】:

LINQ 现在变慢了,但在某些时候它可能会变得更快。 LINQ 的好处是您不必关心它是如何工作的。如果想出一个非常快的新方法,Microsoft 的人员甚至可以在不告诉您的情况下实施它,并且您的代码会快很多。

更重要的是,LINQ 更易于阅读。这应该是足够的理由。

【讨论】:

  • 我喜欢“微软可以实现它”这句话有可能吗,我的意思是如果我不升级框架就可以吗?
  • LINQ 永远不会真正比本机实现更快,因为在一天结束时,它会转换为本机实现。没有特殊的 LINQ CPU 指令和 LINQ 寄存器可用于转换更快的 LINQ 机器代码 - 如果有,它们也将被非 LINQ 代码使用。
  • 不正确,在某些时候某些链接操作可能会变成多线程,甚至在某些时候甚至会利用 GPU。
【解决方案4】:

应该注意for 循环比foreach 快。因此,对于原始帖子,如果您担心渲染器等关键组件的性能,请使用for 循环。

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

【讨论】:

    【解决方案5】:

    如果您将并行 LINQ 用于多核,您可能会获得性能提升。请参阅 Parallel LINQ (PLINQ) (MSDN)。

    【讨论】:

      【解决方案6】:

      我对这个问题很感兴趣,所以我刚才做了一个测试。在 Intel(R) Core(TM) i3-2328M CPU @ 2.20GHz、2200 Mhz、2 核和 8GB RAM 上使用 .NET Framework 4.5.2,运行 Microsoft Windows 7 Ultimate。

      看起来 LINQ 可能比每个循环都快。这是我得到的结果:

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

      如果你们中的一些人可以将此代码复制并粘贴到控制台应用程序中并进行测试,那将会很有趣。 在使用对象(员工)进行测试之前,我尝试使用整数进行相同的测试。那里的 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
      
      }
      

      【讨论】:

      • 这是我得到的:Exists=True Time=274 Exists=True Time=314
      • 你有没有考虑过先做 linq 再做 foreach,这也可能会有所不同
      • 有趣。我收到了Exists=True Time=184 Exists=True Time=135 它在 Apache Gaming 笔记本电脑上(Win 10,C# 7.3)。编译并在调试模式下运行。如果我反转测试,我会得到Exists=True Time=158 Exists=True Time=194。我猜似乎 Linq 更优化了。
      • 这篇文章对对象测试存在误解。虽然 List.Exists 和 .Contains 似乎比 foreach 执行得更好,但确实很有趣。重要的是要注意 .Exists 不是 linq to entity 方法,并且只能在列表上工作,它的 linq 等效方法 .Any() 的执行速度肯定比 foreach 慢。
      • 所有这些不准确的答案和 cmets。不,LINQ 迭代器不会也永远不会比foreach 快。此外,List.Exists 不是 LINQ 方法。
      【解决方案7】:

      这实际上是一个相当复杂的问题。 Linq 使某些事情变得非常容易,如果你自己实现它们,你可能会绊倒(例如 linq .Except())。这尤其适用于 PLinq,尤其适用于 PLinq 实现的并行聚合。

      一般来说,对于相同的代码,linq 会更慢,因为委托调用的开销。

      但是,如果您正在处理大量数据,并对元素应用相对简单的计算,则在以下情况下您将获得巨大的性能提升:

      1. 您使用数组来存储数据。
      2. 您使用 for 循环来访问每个元素(而不是 foreach 或 linq)。

        • 注意:在进行基准测试时,请大家记住——如果连续两次测试使用相同的数组/列表,CPU 缓存会使第二次更快。 *

      【讨论】:

        猜你喜欢
        • 2022-11-17
        • 1970-01-01
        • 2013-10-16
        • 1970-01-01
        • 1970-01-01
        • 2015-10-30
        • 2020-01-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多