Live data from Hacker News

Performance Tuning for .NET Core

reubenbond.github.io

71–78 of 78 posts

Re: Performance Tuning for .NET Core

#71
post #22
post #17

Earlier quoted context omitted.

It is a general design principle for .net libraries that you should seal a class unless you deliberately and carefully design it to be extensible. If a class is unsealed you are basically not able to change it ever again, since someone might have subclassed it and depend on all kinds of internal behavior. So it should only be done very deliberately.

> It is a general design principle for .net libraries Is it? A more typical approach, IMO, is for internal classes to be marked as `internal`, and for `public` classes to be considered part of the public API.

You do both. If you don't need to expose a class you keep it internal. If you do need to expose it, you keep it sealed unless you deliberate design it for extension.

The overarching principle is to keep the API as tight as possible, because as soon as an API is public, you have committed to it and even subtle changes in observable behavior may break some client.

Re: Performance Tuning for .NET Core

#72

Earlier 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…

> 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!

The vast majority of "premature" optimisation happens before the code has been profiled to see which part is slow. In some cases, before the code has _ever been run_. i.e. it is speculative design.

In contrast, you're talking about a function using 30% of the CPU time in a profile, so that's clearly not you.

The longer and less common Knuth quote is below, and it's much more nuanced than the headline. Note that it specifically talks about code optimisation by identifying "critical code" with "measurement tools". That sounds like what you did. Does it not?

> "There is no doubt that the grail of efficiency leads to abuse. Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

> Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified. It is often a mistake to make a priori judgements about what parts of a program are really critical, since the universal experience of programmers who have been using measurement tools has been that their intuitive guesses fail."

- Structured Programming with go to Statements, Donald Knuth, ACM Computing Surveys, Dec. 1974

Re: Performance Tuning for .NET Core

#73
post #41

Earlier 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.

People are still afraid of `var`?

Re: Performance Tuning for .NET Core

#74
post #71
post #22

Earlier quoted context omitted.

> It is a general design principle for .net libraries Is it? A more typical approach, IMO, is for internal classes to be marked as `internal`, and for `public` classes to be considered part of the public API.

You do both. If you don't need to expose a class you keep it internal. If you do need to expose it, you keep it sealed unless you deliberate design it for extension. The overarching principle is to keep the API as tight as possible, because as soon as an API is public, you have committed to it and even subtle changes in observable behavior may break some client.

Usually you define an interface for anything that you want to be overridable and provide some way for consumers to provide their own implementations. Then seal your own implementations.

Then you only need to design your interfaces in such a way that they can easily be implemented by composition.

This is the approach taken in ASP.Net and in WCF; although the latter does a really bad job at making their interfaces user friendly (for even tiny changes you have to re-implement a lot of functionality - which could have been avoided by better interface design).

Re: Performance Tuning for .NET Core

#75
post #70

Earlier quoted context omitted.

This isn't just a design principle for .NET libraries, it's a SOLID design principle. All classes should be inextensible unless they are explicitly designed to be extended.

The open/closed principle doesn’t say that. It says classes should be “open for extension” (usually meaning you are able to inherit from them and add functionality) and “closed for modification”, meaning you aren’t able to change internal implementations. It does not say “everything should be closed by default unless explicitly marked otherwise”...

Composition is still an option, and arguably the default option. Sealing a class does not prevent anyone from extending the functionalities offered by a class.

Re: Performance Tuning for .NET Core

#76

Earlier quoted context omitted.

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".

To var or not to var is purely a "tabs 'n' spaces" debate, but doesn't affect performance.

It will affect the performance of someone trying to read your code.

Re: Performance Tuning for .NET Core

#77

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

In that vein, Nessons has a Stream Fusion library: https://github.com/nessos/Streams

For lightweight threads I recommend https://github.com/Hopac which is an implementation of SML's John Reppy's Concurrent ML on .NET.

Re: Performance Tuning for .NET Core

#78

Earlier quoted context omitted.

So your library speeds up Array /T[] and List Linq operations? That's quite interesting, though usually in my experiences in Linq performance optimization the problem is usually prematurely using the wrong data type for your Linq operation. Given the immediate next bullet point in the article is about foreach operations over List , that would be my top expectation why they were seeing so much allocation in Linq. ToLi…

You just need to be careful not to allow any subsequent modifications of the original collection when doing that (assuming you're using the returned LINQ result), or you'll introduce runtime errors. Typically, my use of ToList or ToArray means I'm guarding against future runtime errors due to collection modification at the expense of memory allocation. It sounds like you know this already, but I like to think I just…

I just often find I need to remind people that there are other data types to consider reifying to beyond List/Array. While I'd probably suggest removing ToList() from Linq as List really does seem to be the wrong data type more often than not, but for whatever reason so many people find it the "easiest" way to deal with Linq. I feel like ToLookup() and ToDictionary() should be more people's best friends when working with Linq. Too often I find bad searches and joins that become so much easier/more performant if some middle product was appropriately stored in a Dictionary or ILookup.

Also with Linq against IQueryable sources, so often ToList/ToArray is used where AsEnumerable would be better. Understanding those monad boundaries is hard, and AsEnumerable doesn't always sound self-explanatory to people when they need to cross those boundaries. (I've thought before that some simple IDE highlighting of which bits of Linq are against IQueryable and which against IEnumerable might help some people think better in Linq.)

Post reply on HN