今天我用性能分析器查看了我所工作的Web应用程序的一个部分。我认为使用Union可能会导致一些延迟,但结果却让我感到惊讶。
造成延迟的原因之一是FirstOrDefault。
这是一个非常简单的LINQ查询,代码如下:
foreach(Report r in reports)
IDTOStudy study = studies.FirstOrDefault(s => s.StudyID == r.StudyID);
我创建了一个小方法来复制我认为FirstOrDefault正在执行的行为。
private IDTOStudy GetMatchingStudy(Report report, IList<IDTOStudy> studies)
{
foreach (var study in studies)
if (study.StudyID == report.StudyID)
return study;
return null;
}
这种方法将FirstOrDefault替换为以下形式:
foreach(Report r in reports)
IDTOStudy study = GetMatchingStudy(r, studies);
通过性能分析器查看新代码运行情况,发现FirstOrDefault
的完成时间是我的新方法的两倍。这真是令人大吃一惊。
我在FirstOrDefault()
查询中肯定做错了什么。是什么呢?
FirstOrDefault()
是否会完成整个查询,然后选择第一个元素?
如何加快速度并使用FirstOrDefault()
?
注1:
我注意到另一个问题是,性能分析工具显示这两种实现都占用了我的CPU。这也是我不喜欢并且没预料到的事情。我添加的额外方法没有减少CPU使用量,只是将其持续时间缩短了一半。
注3:
将这些研究放入字典中可以极大地提高运行时间。这肯定是提交代码的形式。但这并没有回答关于FirstOrDefault的问题。
注2:
这是一个简单的控制台应用程序中请求的示例代码。在大多数情况下,我的运行显示FirstOrDefault需要更长时间。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reactive.Linq;
using System.Reactive.Concurrency;
using System.Diagnostics;
namespace TestCode
{
public class Program
{
public List<IntHolder> list;
public static void Main(string[] args)
{
var prog = new Program();
prog.list = new List<IntHolder>();
prog.Add50000Items();
prog.list.Add(new IntHolder() { Num = 12345 });
prog.Add50000Items();
var stopwatch = new Stopwatch();
stopwatch.Start();
prog.list.FirstOrDefault(n => n.Num == 12345);
stopwatch.Stop();
Console.WriteLine("First run took: " + stopwatch.ElapsedTicks);
var lookingFor = new IntHolder() { Num = 12345 };
stopwatch.Reset();
stopwatch.Start();
prog.GetMatching(lookingFor);
stopwatch.Stop();
Console.WriteLine("Second run took: " + stopwatch.ElapsedTicks);
Console.ReadLine();
}
public void Add50000Items()
{
var rand = new Random();
for (int i = 0; i < 50000; i++)
list.Add(new IntHolder() { Num = rand.Next(100000) });
}
public IntHolder GetMatching(IntHolder num)
{
foreach (var number in list)
if (number.Num == num.Num)
return number;
return null;
}
}
public class IntHolder
{
public int Num { get; set; }
}
}
FirstOrDefault()
应该只生成TOP 1
查询。 - Sergey BerezovskiyFirstOrDefault
和你自己的同样模式的自定义方法之间的区别? - Servy