我试图与LINQ保持联系。最让我困扰的是,即使我对语法有了更好的了解,我也不想在表现力方面无意中牺牲性能。
它们是否是用于“有效LINQ”的良好的集中式信息存储库或书籍?如果失败,您个人最喜欢的高性能LINQ技术是什么?
我主要关心LINQ to Objects,但是当然也欢迎有关LINQ to SQL和LINQ to XML的所有建议。谢谢。
我试图与LINQ保持联系。最让我困扰的是,即使我对语法有了更好的了解,我也不想在表现力方面无意中牺牲性能。
它们是否是用于“有效LINQ”的良好的集中式信息存储库或书籍?如果失败,您个人最喜欢的高性能LINQ技术是什么?
我主要关心LINQ to Objects,但是当然也欢迎有关LINQ to SQL和LINQ to XML的所有建议。谢谢。
yield
(因此是O(N))产生结果。我认为您预测的困难要比实际困难多。
Answers:
只需了解LINQ在内部进行的操作,就可以获得足够的信息,以了解您是否对性能产生了影响。
这是一个简单的示例,其中LINQ有助于提高性能。考虑以下典型的老式方法:
List<Foo> foos = GetSomeFoos();
List<Foo> filteredFoos = new List<Foo>();
foreach(Foo foo in foos)
{
if(foo.SomeProperty == "somevalue")
{
filteredFoos.Add(foo);
}
}
myRepeater.DataSource = filteredFoos;
myRepeater.DataBind();
因此,上面的代码将迭代两次,并分配另一个容器来保存过滤后的值。真是浪费!与之比较:
var foos = GetSomeFoos();
var filteredFoos = foos.Where(foo => foo.SomeProperty == "somevalue");
myRepeater.DataSource = filteredFoos;
myRepeater.DataBind();
这仅迭代一次(绑定转发器时);它只会使用原始容器;filteredFoos
只是一个中间的枚举器。并且,由于某种原因,如果您以后决定不绑定转发器,则不会浪费任何信息。您甚至不需要重复或评估一次。
当你进入非常复杂的顺序操作,可以潜在地通过利用LINQ的固有使用链接和懒惰评估的收获很多。再说一遍,与其他任何事情一样,这只是了解它实际在做什么。
Linq作为一种内置技术,在性能方面有优缺点。.NET团队对扩展方法背后的代码给予了相当大的性能关注,其提供惰性评估的能力意味着对一组对象执行大多数操作的成本分布在需要该操作集的较大算法上。但是,您需要了解一些可能影响或破坏代码性能的事情。
首先,Linq不会神奇地为您的程序节省执行操作所需的时间或内存。否则可能会将这些操作延迟到绝对需要。OrderBy()执行QuickSort,这将花费nlogn时间,就像您在正确的时间编写自己的QuickSorter或使用List.Sort()一样。因此,在编写查询时,请始终记住您要Linq对系列进行的操作。如果不需要进行操作,请尝试重组查询或方法链,以免发生这种情况。
同样,某些操作(排序,分组,聚合)需要了解它们所作用的整个集合。系列中的最后一个元素可能是操作必须从其迭代器返回的第一个元素。最重要的是,由于Linq运算不应更改其可枚举的源,但是它们使用的许多算法(即就地排序)都将因此而产生,因此,这些运算不仅要评估,还要将整个可枚举复制到具体的有限结构中,执行操作并通过操作产生收益。因此,当您在语句中使用OrderBy()并从最终结果中索要一个元素时,将对赋给它的IEnumerable可以产生的所有内容进行评估,将其作为数组存储在内存中,进行排序,然后在一个位置返回一个元素。时间。道德是
最后,Linq方法极大地增加了系统的调用堆栈大小和内存占用。每个必须了解整个集合的操作都会将整个源集合保留在内存中,直到对最后一个元素进行迭代为止,并且对每个元素的求值将涉及调用堆栈,其深度至少是链或子句中方法数量的两倍在您的内联语句中(对每个迭代器的MoveNext()或产生GetEnumerator的调用,以及在此过程中至少对每个lambda的调用)。与执行相同操作的智能工程内联算法相比,这只会导致更大,更慢的算法。Linq的主要优点是代码简单。创建然后排序组值列表的字典不是很容易理解的代码(相信我)。微观优化可以进一步混淆它。如果您最关心性能,那么不要使用Linq。它将增加大约10%的时间开销,并且是自己处理列表的内存开销的几倍。但是,可维护性通常是开发人员最关心的问题,Linq绝对会在此方面提供帮助。
提高性能:如果算法的性能是神圣,不可妥协的第一要务,那么您将使用非托管语言(如C ++)进行编程;.NET将会变得更加缓慢,因为它是一个托管的运行时环境,具有JIT本机编译,托管的内存和额外的系统线程。我会采用“足够好”的哲学。Linq可能会因其性质而导致变慢,但是如果您无法分辨出差异,而您的客户也无法分辨出差异,那么就所有实际目的而言,都没有差异。“过早的优化是万恶之源”;使其发挥作用,然后寻找机会使其性能更高,直到您和您的客户都认为它足够好为止。它可能总是“更好”,但是除非您想手动打包机器代码,否则,
有多种因素会影响性能。
通常,使用LINQ开发解决方案将提供相当合理的性能,因为系统可以构建表达式树来表示查询,而无需在构建查询时实际运行查询。仅当您遍历结果时,它才使用此表达式树来生成并运行查询。
就绝对效率而言,在预定义的存储过程上运行可能会遇到一些性能损失,但是通常采取的方法是使用具有合理性能的系统(例如LINQ)来开发解决方案,而不用担心会损失几分钱性能。如果查询运行缓慢,那么您可能会考虑优化。
现实情况是,通过LINQ完成大多数查询不会有丝毫问题。另一个事实是,如果查询运行缓慢,则与查询本身相比,索引,结构等问题更可能是索引,结构等问题,因此,即使在进行优化时,您通常也不会碰LINQ,正在处理的数据库结构。
对于处理XML,如果您已将文档加载并解析到内存中(例如基于DOM模型的任何东西,或XmlDocument或其他东西),那么与进行某些事件(例如引发事件)的系统相比,您将获得更多的内存使用率。表示找到开始或结束标签,但未构建文档的完整内存版本(例如SAX或XmlReader)。缺点是基于事件的处理通常相当复杂。同样,对于大多数文档来说,这不会有问题-大多数系统具有数GB的RAM,因此占用几MB表示一个XML文档并不是问题(而且您通常至少会处理一些XML文档)按顺序)。只有当您拥有一个占用100 MB的巨大XML文件时,您才会担心这种选择。
请记住,LINQ还允许您遍历内存中的列表等,因此在某些情况下(例如,您将在函数中一次又一次使用一组结果),可以使用.ToList或.ToArray返回结果。有时这可能很有用,尽管通常您希望尝试使用数据库的查询而不是内存查询。
至于个人收藏夹-NHibernate LINQ-它是一个对象关系映射工具,它使您可以定义类,定义映射详细信息,然后从类中获取它来生成数据库,而无需反过来,LINQ支持好(肯定比SubSonic之类的好)。
在linq to SQL中,您不需要太在意性能。您可以按照您认为最可读的方式链接所有语句。Linq最终将所有语句转换为1条SQL语句,最后仅被调用/执行(例如,当您调用a.ToList()
一个var
可以包含该声明没有,如果你想在不同的条件下应用各种额外的语句执行它。最后的执行仅在您要将语句转换为结果(如对象或对象列表)时发生。
有一个名为i4o的codeplex项目,我使用了一段时间,可以在进行相等比较的情况下帮助提高Linq to Objects的性能,例如
from p in People
where p.Age == 21
select p;
http://i4o.codeplex.com/ 我尚未在.Net 4上进行过测试,因此不能安全地说它仍然可以工作,但值得一试。为了使其发挥作用,您通常只需要用一些属性装饰您的类即可指定应为哪个属性建立索引。当我之前使用它时,它只能与相等比较一起使用。