3 ms·
Reflection is fine, just never use it inside a tight loop/ hot code path. I've written a database engine in C#/ .net and I quickly learnt what you can and can'
by velox_io 10y ago
Reflection is fine, just never use it inside a tight loop/ hot code path.
I've written a database engine in C#/ .net and I quickly learnt what you can and can't use. Using the dynamic/ expando parts have insane memory costs.
You have to be very careful what language features you use. If you want performance then static methods are your friend, as are Generics (sometimes sealed classes), arrays & vectors (you start to realise how important CPU cache is). Memory streams & pointers are sometimes needed, but gains are often less than you'd think.
Visual Studio has some really good debugging tools, especially viewing the disassembly (hit a breakpoint then ctrl+alt+d) to see what is really happening.
I love Linq, but it can be awfully slow.
Lastly, when you run tests. Make sure you not only do multiple runs, but also pause in-between. I've seen the jit yield >20% improvements in micro-benchmarks
I will blog about this stuff one day!
- eropple 10y ago> I will blog about this stuff one day! I'd love to read this blog post. One thing to keep in mind, for readers--while LINQ can be awfully slow, it often isn't and should be your first stop (and then improving on it when you find hot paths). I build game engines in C#, and I happily use LINQ to get something done--then I go back, profile my code (anything you're not getting out of your profiler is likely mythical and at best lying to you), and replace as-needed.
- velox_io 10y agoThanks! I guess I should have said that LINQ is a bit of a mine-field; it can generate some very arcane code/ expression trees from relatively simple predicates. I would have loved to have used it (would have saved me writing a query engine), there was simple too much performance overhead (especially memory usage).
- WorldMaker 10y agoOptimizing LINQ is a lot like optimizing Haskell (or to a lesser extent F#) and it isn't so much a minefield as it is dealing with that sort of abrupt paradigm-shift/learning curve wall of a mini embedded functional programming language. I don't think a lot of people understand exactly where some of the eagerness versus laziness boundaries are (which are essentially monad boundaries, from a functional perspective). For instance, I've suggested for some time [1] that one of the strongest things a UX (whether an IDE or an extension to an IDE) could do to help is better mark those boundaries between IQueryable/IEnumerable/IList, as I don't think a lot of people see them. (I've long considered ToList somewhat harmful, especially; it is so painfully rarely the right tool for any task and yet is so easy for people new to LINQ to use as a crutch.) Beyond that there is of course the general rules of optimizing any code: are you using the right data structure for the job and have you balanced caching the expensive operations (queries) against what isn't expensive and doesn't need to be cached. Certainly a lot of optimizations I've seen needed over the years are simply: this lookup would be faster in a Dictionary or a HashSet or an ILookup, instead of an O(n) search through an IEnumerable or IList. (This should be especially obvious any time that you attempt a `join` of any sort against an IEnumerable or IList on either side of the `join` that you need a Dictionary, HashSet, or ILookup on one or both sides.) That sort of data structure optimization is largely the same consideration when you are writing do/while/for/foreach loops directly as it is in the LINQ syntax and it can take a mental leap for developers sometimes to realize it that it is mostly the same problems, even if they sometimes "feel" different. [1] https://1drv.ms/p/s!AkQwwfqxgHzNxOsAj1KSVqxGaiydnQ https://1drv.ms/p/s!AkQwwfqxgHzNxOsAj1KSVqxGaiydnQ
- mandeepj 10y ago> but also pause in-between. I've seen the jit yield >20% improvements in micro-benchmarks Could you please expand on this one? what is the idea behind pause? Did you mean to say the jitted code will be cached and for the same reason it will run faster next time?
- velox_io 10y agoWhile the GC will run under load, the JIT is treated as a luxury and as far as I'm aware, it will only run when there's spare CPU (it makes sense to not interrupt the program while it's busy). If you follow the Build -> Test cycle, the JIT won't kick in (the JIT will run about 10 seconds after heavy load, even while it's running). It's true that the JITted code it cached, this is lost every time you rebuild the application/ library). Speaking of cache, one thing I only came across recently is that if you install the library into the GAC, the JIT seems to be even more aggressive - the code runs faster than a standalone DLL (even with identical stress-testing/ wear-in).
- matthewwarren 10y ago> I love Linq, but it can be awfully slow. You might like this post I wrote http://mattwarren.org/2016/09/29/Optimising-LINQ/ http://mattwarren.org/2016/09/29/Optimising-LINQ/, it talks about LINQ