C# “嵌套 foreach”与“lambda/linq 查询”性能(LINQ-to-Objects)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1044236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Nested foreach" vs "lambda/linq query" performance(LINQ-to-Objects)
提问by JSC
In performance point of view what should you use "Nested foreach's" or "lambda/linq queries"?
从性能的角度来看,您应该使用“嵌套的 foreach”还是“lambda/linq 查询”?
采纳答案by Jon Skeet
Write the clearest code you can, and then benchmark and profile to discover any performance problems. If you dohave performance problems, you can experiment with different code to work out whether it's faster or not (measuring all the time with as realistic data as possible) and then make a judgement call as to whether the improvement in performance is worth the readability hit.
尽可能编写最清晰的代码,然后进行基准测试和分析以发现任何性能问题。如果您确实有性能问题,您可以尝试不同的代码来确定它是否更快(始终使用尽可能真实的数据进行测量),然后判断性能的改进是否值得可读性打。
A direct foreach
approach willbe faster than LINQ in many cases. For example, consider:
一个直接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);
}
Now there are two where
clauses and a select
clause, so every eventual item has to pass through three iterators. (Obviously the two where clauses could be combined in this case, but I'm making a general point.)
现在有两个where
子句和一个select
子句,因此每个最终项都必须通过三个迭代器。(显然,在这种情况下可以将两个 where 子句结合起来,但我是在提出一般观点。)
Now compare it with the direct code:
现在将其与直接代码进行比较:
foreach (var element in list)
{
if (element.X > 2 && element.Y < 2)
{
Console.WriteLine(element.X + element.Y);
}
}
That will run faster, because it has fewer hoops to run through. Chances are that the console output will dwarf the iterator cost though, and I'd certainly prefer the LINQ query.
那会跑得更快,因为它要穿过的箍更少。不过,控制台输出可能会使迭代器成本相形见绌,我当然更喜欢 LINQ 查询。
EDIT: To answer about "nested foreach" loops... typically those are represented with SelectMany
or a second from
clause:
编辑:要回答有关“嵌套 foreach”循环的问题……通常用SelectMany
或 第二个from
子句表示:
var query = from item in firstSequence
from nestedItem in item.NestedItems
select item.BaseCount + nestedItem.NestedCount;
Here we're only adding a single extra iterator, because we'd already be using an extra iterator per item in the first sequence due to the nested foreach
loop. There's still a bit of overhead, including the overhead of doing the projection in a delegate instead of "inline" (something I didn't mention before) but it still won't be very different to the nested-foreach performance.
这里我们只添加了一个额外的迭代器,因为由于嵌套foreach
循环,我们已经在第一个序列中为每个项目使用了一个额外的迭代器。仍然有一些开销,包括在委托中而不是“内联”中进行投影的开销(我之前没有提到过),但它仍然与嵌套 foreach 性能没有太大区别。
This is not to say you can't shoot yourself in the foot with LINQ, of course. You can write stupendously inefficient queries if you don't engage your brain first - but that's far from unique to LINQ...
当然,这并不是说你不能用 LINQ 用脚射击自己。如果您不先动动脑子,您可能会编写非常低效的查询 - 但这远不是 LINQ 独有的......
回答by Marc Gravell
It is more complex on that. Ultimately, much of LINQ-to-Objects is (behind the scenes) a foreach
loop, but with the added overhead of a little abstraction / iterator blocks / etc. However, unless you do very different things in your two versions (foreach vs LINQ), they should both be O(N).
在这方面更复杂。最终,大部分 LINQ-to-Objects 是(在幕后)一个foreach
循环,但是增加了一些抽象/迭代器块/等的开销。但是,除非您在两个版本中做非常不同的事情(foreach vs LINQ) ,它们都应该是 O(N)。
The real question is: is there a better way of writing your specificalgorithm that means that foreach
would be inefficient? And can LINQ do it for you?
真正的问题是:是否有更好的方法来编写您的特定算法,这意味着foreach
效率低下?LINQ 可以为您做吗?
For example, LINQ makes it easy to hash / group / sort data.
例如,LINQ 可以轻松地对数据进行散列/分组/排序。
回答by Amy B
If you do
如果你这样做
foreach(Customer c in Customer)
{
foreach(Order o in Orders)
{
//do something with c and o
}
}
You will perform Customer.Count * Order.Count iterations
您将执行 Customer.Count * Order.Count 迭代
If you do
如果你这样做
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
}
You will perform Customer.Count + Order.Count iterations, because Enumerable.Join is implemented as a HashJoin.
您将执行 Customer.Count + Order.Count 迭代,因为 Enumerable.Join 是作为 HashJoin 实现的。
回答by Drithyin
It's been said before, but it merits repeating.
之前已经说过,但值得重复。
Developers never know where the performance bottleneck is until they run performance tests.
开发人员在运行性能测试之前永远不知道性能瓶颈在哪里。
The same is true for comparing technique A to technique B. Unless there is a dramatic difference then you just have to test it. It might be obvious if you have an O(n) vs O(n^x) scenario, but since the LINQ stuff is mostly compiler witchcraft, it merits a profiling.
将技术 A 与技术 B 进行比较也是如此。除非存在显着差异,否则您只需对其进行测试。如果您有 O(n) 与 O(n^x) 方案,这可能很明显,但由于 LINQ 的东西主要是编译器巫术,因此值得分析。
Besides, unless your project is in production and you have profiled the code and found that that loop is slowing down your execution, leave it as whichever is your preference for readability and maintenance. Premature optimization is the devil.
此外,除非您的项目正在生产中并且您已经分析了代码并发现该循环正在减慢您的执行速度,否则将其保留为您对可读性和维护的偏好。过早的优化是魔鬼。
回答by Denis Troller
A great benefit is that using Linq-To-Objects queries gives you the ability to easily turn the query over to PLinq and have the system automatically perform he operation on the correct number of threads for the current system.
一个很大的好处是,使用 Linq-To-Objects 查询使您能够轻松地将查询转换为 PLinq,并让系统自动对当前系统的正确线程数执行操作。
If you are using this technique on big datasets, that's an easily become a big win for very little trouble.
如果您在大型数据集上使用这种技术,那将很容易成为一个非常小的麻烦。