升级到ReSharper5后,它为我提供了更多有关代码改进的有用提示。我现在到处看到的一个是用LINQ查询替换foreach语句的提示。举个例子:
private Ninja FindNinjaById(int ninjaId)
{
foreach (var ninja in Ninjas)
{
if (ninja.Id == ninjaId)
return ninja;
}
return null;
}
建议使用LINQ替换为以下内容:
private Ninja FindNinjaById(int ninjaId)
{
return Ninjas.FirstOrDefault(ninja => ninja.Id == ninjaId);
}
这看起来很好,我确信在替换这个foreach时性能没有问题。但这是我应该做的一般事情吗?或者我可能遇到所有这些LINQ查询的性能问题?
答案 0 :(得分:18)
您需要了解LINQ查询将在“幕后”进行的操作,并将其与运行代码进行比较,然后才能知道是否应该更改它。一般来说,我并不是说你需要知道将要生成的确切代码,但你需要知道它将如何执行操作的基本思路。在你的例子中,我猜测LINQ基本上和你的代码一样工作,因为LINQ语句更紧凑和描述性,我更喜欢它。但有时候,LINQ可能不是理想的选择,尽管可能并不多。一般来说,我认为几乎任何循环结构都可以被等效的LINQ结构替换。
答案 1 :(得分:15)
首先让我说我喜欢LINQ的表现力并且一直使用它而没有任何问题。
但是在性能方面存在一些差异。通常它们足够小,可以忽略,但在应用程序的关键路径中,有时可能需要优化它们。
以下是您应该注意的一组差异,这可能与性能有关:
GetEnumerator
方法来迭代它。调用GetEnumerator
通常可以确保创建另一个对象。IEnumerator
界面迭代集合。接口调用比普通方法调用慢一点。IEnumerator
对象通常需要处理,或者至少必须调用Dispose
。如果需要考虑性能问题,请尝试使用for
而不是foreach
。
同样,我喜欢LINQ和我不记得因为性能而决定不使用LINQ (对象)查询。所以,不要做任何过早的优化。首先从最易读的解决方案开始,然后在需要时进行优化。所以个人资料,个人资料和个人资料。
答案 2 :(得分:7)
我们发现性能问题的一件事是创建大量lambdas并迭代小集合。转换后的样本会发生什么?
Ninjas.FirstOrDefault(ninja => ninja.Id == ninjaId)
首先,创建(生成的)闭包类型的新实例。托管堆中的新实例,有些适用于GC。 其次,从该闭包中的方法创建新的委托实例。 然后调用方法FirstOrDefault。它能做什么? 它迭代集合(与原始代码相同)并调用委托。
所以基本上,你在这里添加了4件事: 1.创建闭包 2.创建委托 3.通过代表打电话 4.收集闭包和委托
如果您多次调用FindNinjaById,您将添加此内容可能是重要的性能打击。当然,衡量它。
如果用(等效)
替换它Ninjas.Where(ninja => ninja.Id == ninjaId).FirstOrDefault()
它补充说 5.为迭代器创建状态机(“Where”正在产生函数)
答案 3 :(得分:6)
确切知道的唯一方法是剖析。是的,某些查询可能会更慢。但是当你看看ReSharper在这里取代了什么时,它本质上是一样的,以不同的方式完成。 ninjas循环,每个Id都被检查。如果有的话,你可以说这个重构归结为可读性。您觉得哪两个更容易阅读?
更大的数据集肯定会产生更大的影响,但正如我所说,简介。这是确定此类增强是否会产生负面影响的唯一方法。
答案 4 :(得分:5)
我们已经构建了大量的应用程序,LINQ遍布各处。永远不会让我们放慢脚步。
编写非常慢的LINQ查询是完全可能的,但是修复简单的LINQ语句要比/ if / for / return算法更容易。
采取resharper的建议:)
答案 5 :(得分:5)
一则轶事:当我刚刚了解C#3.0和LINQ时,我仍然在“当你有一把锤子,一切看起来像一个钉子”阶段。作为一项学校作业,我应该写一个连接四/四连接游戏作为对抗性搜索算法的练习。我在整个程序中使用了LINQ。在一个特殊的情况下,如果我把它放在一个特定的列中,我需要找到一个游戏块落下的行。 LINQ查询的完美用例!事实证明这很慢。但是,LINQ不是问题,问题是我正在搜索开始。我通过保存一个查找表来优化它:一个整数数组,包含游戏板每列的行号,在插入游戏时更新该表。毋庸置疑,这要快得多。
经验教训:首先优化算法,LINQ等高级构造实际上可以更容易。
尽管如此,创建所有代表的成本确实很高。另一方面,利用LINQ的懒惰性质也可以带来性能优势。如果你手动循环一个集合,你几乎被迫创建中间List<>
,而使用LINQ,你基本上流式传输结果。
答案 6 :(得分:3)
以上内容完全相同。
只要您正确使用LINQ查询,就不会遇到性能问题。如果您正确使用它,由于创建LINQ的人员的技能,它更可能更快。
创建自己的唯一好处就是如果你想要完全控制,或者LINQ没有提供你需要的东西,或者你想要更好的调试能力。
答案 7 :(得分:3)
关于LINQ查询的一个很酷的事情是它使dead simple转换为并行查询。取决于你正在做什么,它可能会或可能不会更快(一如既往,简介),但它仍然非常整洁。
答案 8 :(得分:3)
为了增加我自己使用LINQ的经验,其中性能确实很重要 - 使用Monotouch - 差异仍然微不足道。
你在3GS iPhone上“残疾”到大约46mb的RAM和620mhz的ARM处理器。不可否认,代码是AOT编译的,但即使在模拟器上它是JIT并且经历了一系列间接,对于1000个对象的集合,差异是十分之一毫秒。
除了Windows Mobile,您还必须担心性能成本 - 而不是在四核8gb服务器上运行的大型ASP.NET应用程序或具有双重分数的桌面。这种情况的一个例外是大型对象集,尽管可能无论如何都会延迟加载,并且初始查询任务将在数据库服务器上执行。
这在Stackoverflow上有点陈词滥调,但使用更短的更易读的代码,直到100毫秒确实很重要。