One of the tips is to avoid Linq, which many .NET developers are hesitant to do. I made a library that lets you use Linq style convenience functions without a performance hit in many cases: https://github.com/jackmott/LinqFaster
People abuse Linq a lot though; enormously complex queries over very large datasets without really knowing what you are doing. When people need .Each, some will just do .ToList().Each(. Etc. I found a bigger issue even with abuse/overuse) (or use at all really) of dynamic. I wish there was a way of to ban it at compile time.
Performance Tuning for .NET Core
41–50 of 78 posts
Re: Performance Tuning for .NET Core
#42Earlier quoted context omitted.
People abuse Linq a lot though; enormously complex queries over very large datasets without really knowing what you are doing. When people need .Each, some will just do .ToList().Each(. Etc. I found a bigger issue even with abuse/overuse) (or use at all really) of dynamic. I wish there was a way of to ban it at compile time.
I will challenge every use of dynamic (and var, for that matter), unless it's used in the very few appropriate cases.
I find it makes most (but not all) code more readable, particularly given that we have great IDEs/tooling in the .NET world.
Re: Performance Tuning for .NET Core
#43 void GetValue (string key, out SomeBigType result) {
if (_cache.TryGetValue(key, out result))
return;
result = new SomeBigType(key, ...);
_cache[key] = result;
}
In most scenarios this function might not get inlined, because the cache miss path makes the function bigger. If you use the aggressive inlining attribute you might be able to convince the JIT to inline it, but once the function gets bigger it doesn't inline anymore.However, if you pull the cache miss out:
void GetValue (string key, out SomeBigType result) {
if (_cache.TryGetValue(key, out result))
return;
GetValue_Slow(key, out result);
}
void GetValue_Slow (string key, out SomeBigType result) {
result = new SomeBigType(key, ...);
_cache[key] = result;
}
You will find that in most cases, GetValue is inlined and only GetValue_Slow produces a function call. This is especially true in release builds and you can observe it in the built-in Visual Studio profiler or by looking at method disassembly.(Keep in mind that many debuggers - including VS's - will disable JIT optimization if you start an application under the debugger or attach to it. You can disable this.)
This tip applies to both desktop .NET Framework and .NET Core, in my testing (netcore is generally better at inlining, though!) If you're writing any performance-sensitive paths in a library I highly recommend doing this. It can make the code easier to read in some cases anyway.
Re: Performance Tuning for .NET Core
#44Earlier quoted context omitted.
I will challenge every use of dynamic (and var, for that matter), unless it's used in the very few appropriate cases.
`var` is entirely syntactic sugar (compile-time type inference) and there's no runtime cost associated with it. I find it makes most (but not all) code more readable, particularly given that we have great IDEs/tooling in the .NET world.
Re: Performance Tuning for .NET Core
#45Earlier quoted context omitted.
I failed to see how your anecdote relate to your ax-grindy assertion that premature optimization is bad. You wrote your code, you profiled it, you found one function taking 30% of the time, you optimized that function.
We can always end up with a tautology interpretation of premature optimization, in which case it cannot be bad, if it was bad, it wasn't premature! While this may no include you, a great many forums and advise areas on the internet, and elsewhere, would discourage you from even worrying about a detail like this. Asking questions about this will just get you a knuth quote. I sometimes wonder if the reason so much soft…
So when you do have such an issue, and you want to make it clear that it's not a premature optimization, you should mention that it's a hot path as determined by profiling (or whatever other technique). Then you won't get the Knuth quote.
Re: Performance Tuning for .NET Core
#46> Mark classes as sealed by default Please, no! This shouldn't be the default - it's a constant bugbear of mine where I want to extend a class from a library, and I can't because it's been sealed for no good reason.
How do you know it's not been done for a good reason? Designing classes for extensibility is not easy. Furthermore, you can make classes extensible later on, but you can't do the reverse without breaking the API.
Designing for extensibility is not easy in the context of virtual methods. Every virtual method can be overridden, which means that you effectively need to define contracts for all your methods that can be overridden, and only call them in ways that respect those contracts. In a language where everything is virtual by default, like Java, this means all non-private methods. Which is not good, because most of the time, the reason why you're making a method public is to allow calling it, not to allow overriding. That's why C# made "virtual" explicit opt-in.
But for inheritance, there's no such issue. If someone inherits from your class, they can't break your invariants - they still have to invoke your constructor, and they don't have access to any private state. In C#, they also can't override public and protected members, unless those are declared virtual. Thus, there's no safety or correctness reason to prohibit derivation.
It should also be noted that there's no perf gain from declaring a class "sealed", unless it has virtual methods (normally, inherited from a base class, because it doesn't make any sense to have virtual methods declared in a sealed class). Thus, the only time to do so is when you have a class hierarchy, for leaf nodes in that hierarchy.
Re: Performance Tuning for .NET Core
#47> Mark classes as sealed by default Please, no! This shouldn't be the default - it's a constant bugbear of mine where I want to extend a class from a library, and I can't because it's been sealed for no good reason.
Please yes! Classes should be designed for extension on purpose, not as oversight, one of the SOLID pillars. Taking advantage of an oversight is an open door for fragile base class problems and hard to track down bugs.
If the author has spent time optimising to that level, overriding probably isn't necessary or warranted in that area.
Re: Performance Tuning for .NET Core
#48Earlier quoted context omitted.
I understand the argument for composition-of-inheritance but they rarely apply when you actually need to do it. Often it's to reach in and fix a bug or enhance the behaviour of an existing component. You simply can't do that with composition. Without inheritance (if the class is sealed) I often end up having to re-write the entire component or simply accept my fate. So that is a lose-lose situation.
That's where delegation comes in. You wrap each public method of Foo in another class call MyFoo and then fix the one method you care about. With C# and R# it's a simple matter of: Create a new class Create a private variable: private Foo _foo Click on _foo Resharper menu -> Generate Code -> create Delegating members.
Secondly this code generation solution is just re-implementing inheritance again poorly and with the above mentioned limitation. I fail to see how code generating a proxy is any way better than (or significantly different from) inheritance.
Re: Performance Tuning for .NET Core
#49Earlier quoted context omitted.
`var` is entirely syntactic sugar (compile-time type inference) and there's no runtime cost associated with it. I find it makes most (but not all) code more readable, particularly given that we have great IDEs/tooling in the .NET world.
I agree, by using var you need to name your variable better therefore making your code more readable. Rather than relying on the interface/class definition to explain to someone why you used "obj".
Re: Performance Tuning for .NET Core
#50> Mark classes as sealed by default Please, no! This shouldn't be the default - it's a constant bugbear of mine where I want to extend a class from a library, and I can't because it's been sealed for no good reason.
I had the same thought when I saw that. There seems to be a trend to seal and lock down classes preventing any kind of extension. It sort of misses one of the main benefits of OOP and I know what I'm doing.