sti*_*k81 18 .net c# linq resharper performance
升级到ReSharper5后,它为我提供了更多有关代码改进的有用提示.我现在到处看到的一个是用LINQ查询替换foreach语句的提示.举个例子:
private Ninja FindNinjaById(int ninjaId)
{
foreach (var ninja in Ninjas)
{
if (ninja.Id == ninjaId)
return ninja;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
建议使用LINQ替换为以下内容:
private Ninja FindNinjaById(int ninjaId)
{
return Ninjas.FirstOrDefault(ninja => ninja.Id == ninjaId);
}
Run Code Online (Sandbox Code Playgroud)
这看起来很好,我确信在替换这个foreach时性能没有问题.但这是我应该做的一般事情吗?或者我可能遇到所有这些LINQ查询的性能问题?
tva*_*son 18
您需要了解LINQ查询将在"引擎盖下"执行的操作,并将其与运行代码进行比较,然后才能知道是否应该更改它.一般来说,我并不是说你需要知道将要生成的确切代码,但你需要知道它将如何执行操作的基本思路.在你的例子中,我猜测LINQ基本上和你的代码一样工作,因为LINQ语句更紧凑和描述性,我更喜欢它.但有时候,LINQ可能不是理想的选择,尽管可能并不多.一般来说,我认为几乎任何循环结构都可以被等效的LINQ结构替换.
Ste*_*ven 15
首先让我说,我喜欢LINQ的表现力,并且一直使用它没有任何问题.
但是在性能方面存在一些差异.通常它们足够小,可以忽略,但在应用程序的关键路径中,有时可能需要优化它们.
以下是您应该注意的一组差异,这可能与性能有关:
GetEnumerator
集合上的方法来迭代它.调用GetEnumerator
通常可以确保创建另一个对象.IEnumerator
界面迭代集合.接口调用比普通方法调用慢一点.IEnumerator
通常需要处理对象,或者至少Dispose
必须调用对象.当性能是一个问题,也尝试使用for
过foreach
.
再一次,我喜欢LINQ,我不记得因为性能而决定不使用LINQ(对象)查询.所以,不要做任何过早的优化.首先从最易读的解决方案开始,然后在需要时进行优化.所以型材,异型材和型材.
我们发现性能问题的一件事是创建大量的lambdas并迭代小集合.转换后的样本会发生什么?
Ninjas.FirstOrDefault(ninja => ninja.Id == ninjaId)
Run Code Online (Sandbox Code Playgroud)
首先,创建(生成的)闭包类型的新实例.托管堆中的新实例,有些适用于GC.其次,从该闭包中的方法创建新的委托实例.然后调用方法FirstOrDefault.它能做什么?它迭代集合(与原始代码相同)并调用委托.
所以基本上,你在这里添加了4件事:1.创建闭包2.创建委托3.通过委托调用4.收集闭包和委托
如果你多次调用FindNinjaById,你将添加这个可能是重要的性能打击.当然,衡量它.
如果用(等效的)替换它
Ninjas.Where(ninja => ninja.Id == ninjaId).FirstOrDefault()
Run Code Online (Sandbox Code Playgroud)
它添加5.为迭代器创建状态机("Where"正在产生函数)
确切知道的唯一方法是剖析.是的,某些查询可能会更慢.但是当你看看ReSharper在这里取代了什么时,它本质上是一样的,以不同的方式完成.ninjas循环,每个Id都被检查.如果有的话,你可以说这个重构归结为可读性.您觉得哪两个更容易阅读?
更大的数据集肯定会产生更大的影响,但正如我所说的,简介.这是确定此类增强是否会产生负面影响的唯一方法.
我们已经构建了大量的应用程序,LINQ遍布各处.永远不会让我们放慢脚步.
编写非常慢的LINQ查询是完全可能的,但是修复简单的LINQ语句要比/ if/for/return算法更容易.
拿resharper的建议:)
轶事:当我刚开始了解C#3.0和LINQ时,我还处于“当您有锤子时,一切看起来都像钉子”的阶段。作为一项学校作业,我应该编写一个四/四连接的连续游戏作为对抗搜索算法的练习。我在整个程序中都使用LINQ。在一个特定的情况下,我需要找到一个将游戏放置在特定列中的行。LINQ查询的完美用例!事实证明这确实很慢。但是,LINQ并不是问题,问题在于我一直在寻找。我通过保留一个查找表来优化此效果:一个整数数组,其中包含游戏板每一列的行号,并在插入游戏部件时更新该表。不用说,这快得多了。
经验教训:首先优化您的算法,像LINQ这样的高级构造实际上可能使它更容易。
话虽如此,创建所有这些代表需要一定的成本。另一方面,利用LINQ的惰性特性也可以带来性能优势。如果您手动遍历一个集合,则几乎被迫创建中间体List<>
,而使用LINQ,您基本上可以流式传输结果。