Are simple LINQ queries on an IEnumerable
lightweight or heavyweight? How do they compare to writing for
or foreach
loops by
According to LINQ In Action (pg.198):
"LINQ does not come for free. LINQ queries cause additional work, object creations, and pressure on the garbage collector. The additional cost of using LINQ can vary a lot depending on the query. It can be as low as 5 percent, but can sometimes be around 500 percent."
About the only real performance overhead of LINQ-to-objects over doing it yourself are the few extra objects created to help with the enumeration and the function calls. In short, unless you use it in a way it wasn't designed to, it won't hurt your performance unless you're doing very high-perf stuff.
In that case, I'd implement it the LINQ way first, and let your performance testing tell you in which specific places you may need to consider doing it differently. For quite a bit of code, ease of maintenance trumps pure performance.
One great way to convince yourself about LINQ is to use LINQPad. It allows you to output the IL for your LINQ and non-LINQ implementations (as well as output the SQL if you're using LINQ2SQL).
Often times when I have a question about what is exactly happening "behind the scenes" (as your co-worker is wondering), I go to the IL and find out for myself. The vast majority of the time what I've seen is that LINQ's implmenetation is superb.
The authors of LINQ in Action did some benchmarking with for, foreach, List<T>.FindAll
, and LINQ queries that all did the same thing. Depending on how the queries were constructed, LINQ was only about 10% slower. As they put it,
LINQ does not come for free.
LINQ is a complex subject, but depending on what you do with it, it doesn't have to add a lot of overhead. Generally LINQ has been built to rely on deferred execution wherever possible, to save memory and CPU until you actually need it.
However, you have to be aware how the different query operators work, because changing the flow of a query could drastically alter how it's executed. Simple queries as you describe are usually not a problem, but operators like Reverse()
and conversion operators can throw some wrenches because they require immediate iteration of the result set. There are often multiple ways to write the same query, and depending on how you construct it, you can be looking at a minimal performance loss or you could make it twice as slow as the equivalent loops.
The convienence and conciseness it offers far outweighs any performance considerations for most of my day to day coding though. Never pre-optimize!
There's the overhead of invoking delegates, but that's generally fairly low.
Then there's the overhead of all the iterators involved - usually one iterator per extra clause in the query. Again, not a huge amount, but not nothing either.
Do you have an actual application in mind? If so, how important is the performance in the bit which could be done in LINQ? In my experience these bits are usually not the bottleneck, so if LINQ decreases the performance very slightly it really doesn't matter. LINQ can contribute greatly to the readability of your solution though.
Note that the performance in your example is quite different because the two pieces of code are doing very different things. Your LINQ example will execute in the blink of an eye because it's not actually running the query - it's just setting it up. If you call ToList()
at the end then it's basically equivalent to your second example. This sort of thing is very important to remember when doing performance comparisons!
Another thing to bear in mind - you don't have to use the query expression syntax. If you're just filtering (or just projecting) I usually find it makes more sense to call the extension method with normal dot notation:
var lowNums = numbers.Where(n => n < 5);
Here is my general rule for LINQ
Use LINQ when the solution is more expressive. Only switch to a less expressive but faster solution when a profiler has proved that the LINQ query is a source of problem.