LINQ 语句比 foreach 循环快吗?

我正在写一个网格渲染管理器,认为这将是一个好主意,组所有的网格使用相同的着色器,然后渲染这些,而我在该着色器通行证。

我目前正在使用 foreach循环,但不知道如果使用 LINQ 可能会给我一个性能提高?

167298 次浏览

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

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

如果对多核使用并行 LINQ,可能会提高性能。参见 并行 LINQ (PLINQ)(MSDN)。

LINQ-to-Objects 一般来说将添加一些边际开销(多个迭代器等)。它仍然需要做循环,还有有委托调用,还有通常需要做一些额外的解引用来获得捕获的变量等。在大多数代码中,这几乎是不可检测的,而且 超过是由更简单的代码来理解的。

对于其他的 LINQ 提供商,比如 LINQ-to-SQL,因为查询可以在服务器上进行过滤,所以它应该是 好多了而不是平面的 foreach,但是最有可能的情况是你不会做一个整体的 "select * from foo" 无论如何,所以这不是一个公平的比较 必须的

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

LINQ 现在比较慢,但是在某些时候可能会变得更快。LINQ 的好处是你不必关心它是如何工作的。如果一个新的方法被想出来,这是令人难以置信的快,在微软的人可以实现它,甚至不告诉你,你的代码会快得多。

更重要的是,LINQ 更容易阅读,这应该足够了。

也许应该注意到,for循环比 foreach更快。因此,对于最初的文章,如果您担心关键组件(如渲染器)的性能,可以使用 for循环。

参考文献: 在.NET 中,哪个循环运行得更快,对于 & # 39; 或 & # 39; foreach & # 39; ?

我对这个问题很感兴趣,所以我刚才做了一个测试。吸毒。NET Framework 4.5.2搭载于 Intel (R) Core (TM) i3-2328M CPU@2.20 GHz,2200 Mhz,2核心,8GB 内存,运行 Microsoft Windows 7 Ultimate。

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

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

如果你们中的一些人能够将这些代码复制粘贴到一个控制台应用程序中并进行测试,那将会非常有趣。 在使用对象(Employee)进行测试之前,我使用整数进行了相同的测试。

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


}

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

通常,对于相同的代码,linq 会慢一些,这是因为委托调用的开销。

但是,如果您处理大量数据,并对元素应用相对简单的计算,那么如果:

  1. 使用数组存储数据。
  2. 使用 for 循环访问每个元素(与 foreach 或 linq 相反)。

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

在.NET core 7中,对 LINQ 性能的.Min. Max、 .Average 和.Sum 进行了一些重要的更新 参考文献: < a href = “ https://devblogs.microsoft.com/dotnet/Performance _ better _ in _ net _ 7/# linq”rel = “ nofollow norefrer”> https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/#linq

这里是一个基准从邮件。 Benchmark of .NET Core 6 vs 7 LINQ methods

如果将其与 ForEach 循环进行比较,那么很明显,在。NET 6中的 ForEach 循环更快。NET 7的 LINQ 方法: enter image description here

这是使用 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);
}
}

进去。NET Core 6和早期版本中提到的方法比自己执行 foreach 循环和查找数组中对象的最小值、最大值、平均值或汇总要慢。

但是在.NETCore7中,性能的提高使得这些构建 LINQ 方法实际上要快得多。 尼克 · 查普萨斯(Nick Chapsas)在 YouTube 上的一个基准视频中展示了这一点

因此,如果要计算和、最小、最大或平均值,应该使用 LINQ 方法,而不是使用 foreach 循环。NET Core 7以后的版本(至少从性能角度来看)