2009-06-25 107 views

回答

55

编写最清晰的代码,然后进行基准测试和配置文件发现任何性能问题。如果您的确实有存在性能问题,您可以尝试使用不同的代码来确定是否更快(使用尽可能真实的数据测量所有时间),然后判断性能改进是否值得可读性受到打击。

直接foreach方法在许多情况下比LINQ更快。例如,考虑:

var query = from element in list 
      where element.X > 2 
      where element.Y < 2 
      select element.X + element.Y; 

foreach (var value in query) 
{ 
    Console.WriteLine(value); 
} 

现在有两个where条款和select条款,所以每一个最终的项目必须经过三个迭代器。 (显然这两个where子句可以在这种情况下合并,但我在做一般点)

现在有了直接的代码进行比较:

foreach (var element in list) 
{ 
    if (element.X > 2 && element.Y < 2) 
    { 
     Console.WriteLine(element.X + element.Y); 
    } 
} 

这将运行得更快,因为它有更少的篮球穿过。尽管如此,控制台输出可能会使迭代器成本变得更低,我当然更喜欢LINQ查询。

编辑:为了回答关于“嵌套的foreach”循环通常...那些体表示SelectMany或第二from条款:

var query = from item in firstSequence 
      from nestedItem in item.NestedItems 
      select item.BaseCount + nestedItem.NestedCount; 

这里我们只需要添加一个额外的迭代,因为我们”由于嵌套的foreach循环,d已经在第一个序列中的每个项目使用了一个额外的迭代器。还有一些开销,包括在委托中进行投影的开销,而不是“内联”(我之前没有提到过),但它与嵌套的foreach性能仍然不会有很大的不同。

这并不是说你不能用LINQ拍摄自己的脚,当然。如果你不首先使用你的大脑,那么你可以写出效率低下的查询 - 但这与LINQ的独特之处不同......

+13

第一句应作为横幅打印出来,挂在每个编程部门。 – 2012-11-02 03:18:39

+1

乔恩...你真棒...最衷心的感谢! – 2013-08-22 06:42:50

11

这是比较复杂的。最终,大部分LINQ到对象都是(幕后)一个foreach循环,但增加了一些抽象/迭代器块/等的额外开销。但是,除非你在两个版本中做了非常不同的事情(foreach vs LINQ ),它们都应该是O(N)。

真正的问题是:是否有更好的方式来编写您的特定的算法,这意味着foreach会效率低下? LINQ可以为你做吗?

例如,LINQ可以很容易地散列/分组/排序数据。

22

如果你

foreach(Customer c in Customer) 
{ 
    foreach(Order o in Orders) 
    { 
    //do something with c and o 
    } 
} 

您将执行Customer.Count *订购。计数迭代


如果你

var query = 
    from c in Customer 
    join o in Orders on c.CustomerID equals o.CustomerID 
    select new {c, o} 

foreach(var x in query) 
{ 
    //do something with x.c and x.o 
} 

您将执行Customer.Count + Order.Count迭代,因为Enumerable.Join作为一个HashJoin实现。

+0

很好的解答和很好的解释 – 2009-06-25 14:39:37

+4

这是因为你运行两种不同的算法;你正在比较苹果和橘子。我不明白这与提出的问题有什么关系。 – mquander 2009-06-25 14:50:20

2

之前已经说过了,但它值得重复。

开发人员在运行性能测试之前不会知道性能瓶颈的位置。

将技术A与技术B进行比较也是如此。除非存在显着差异,否则您只需对其进行测试即可。如果你有一个O(n)和O(n^x)的场景,这可能是显而易见的,但是由于LINQ的东西大部分是编译器巫术,所以它值得分析。此外,除非您的项目正在生产中,并且您已经对代码进行了剖析并发现该循环会减慢执行速度,否则请将其作为您偏好的可读性和维护的依据。不成熟的优化是魔鬼。

2

一个很大的好处是,使用Linq-To-Objects查询可以轻松将查询转换为PLinq,并让系统自动对当前系统的正确线程数执行操作。

如果你在大数据集上使用这种技术,这很容易成为一个很小的麻烦的大赢家。