Live data from Hacker News

Performance Improvements in .NET 10

devblogs.microsoft.com

81–90 of 98 posts

Re: Performance Improvements in .NET 10

#81
post #54

Earlier quoted context omitted.

This is wishful thinking. It’s the same as other layers we have like auto-vectorization where you don’t know if it’s working without performance analysis. The complexity compounds and reasoning about performance gets harder because the interactions get more complex with abstractions like these. Also, the more I work with this stuff the more I think trying to avoid memory management is foolish. You end up having to th…

> It’s the same as other layers we have like auto-vectorization where you don’t know if it’s working without performance analysis. The complexity compounds and reasoning about performance gets harder because the interactions get more complex with abstractions like these. Reasoning about performance is hard as it is, given nondeterministic optimisations by the CPU. Furthermore, a program that's optimal for one impleme…

I enjoy reading your comments here. Thanks for sharing your knowledge, I'll watch the talk.

> Yes, and arenas may give such usage patterns a similar CPU/RAM knob to tracing collectors, but this level of control isn't free. In the end you have to ask yourself if what you're gaining is worth the added effort.

For me using them has been very easy/convenient. My earlier attempts with Zig used alloc/defer free everywhere and it required a lot of thought to not make mistakes. But on my latest project I'm using arenas and it's much more straightforward.

Re: Performance Improvements in .NET 10

#82

Earlier quoted context omitted.

The breaking changes are very well documented and are esoteric in nature. https://learn.microsoft.com/en-us/dotnet/core/compatibility/... Scott Hanselman has a very short blog on how 20 year old code is upgraded to the latest .NET in just a few short minutes: https://www.hanselman.com/blog/upgrading-a-20-year-old-unive...

Bs, basically, the docs about upgrading between frameworks and what works with what is actually pretty current and often disappears after some years. Especially anything about edge cases. Several upgrades also demands that you do the upgrade version by version. It is tedious work if you don't have a full understanding of the app. Nuget has also become a complete dependency hell. Today you often have to point out what…

I just upgraded a .NET Framework 3.5 Windows application to .NET 9, with little to no issues. I even decided to remake it as a WinUI app instead of leaving it in WinForms. The entire process took me less than 2 weeks, of just casual development

Re: Performance Improvements in .NET 10

#83

Earlier quoted context omitted.

Bs, basically, the docs about upgrading between frameworks and what works with what is actually pretty current and often disappears after some years. Especially anything about edge cases. Several upgrades also demands that you do the upgrade version by version. It is tedious work if you don't have a full understanding of the app. Nuget has also become a complete dependency hell. Today you often have to point out what…

"Several upgrades also demands that you do the upgrade version by version" This seems unlikely. Do you have a source?

I upgraded hundreds of projects. The docs with breaking changes are by version. For smaller solutions you can create a new solution and pull in the code and try to fix everything that breaks. There is also an upgrade tool that can work for smaller projects. But the fastest way for normal sized solutions is to update version by version up to the closest LTS. Then you can go LTS to LTS. .NET does also not only break in code, it breaks in behavior so you really want to test those changes in isolation.

Re: Performance Improvements in .NET 10

#84

Earlier quoted context omitted.

GC is problematic for cross-language foundational libraries though (unless they run on the same VM of course).

But what’s so bad about that Clojure and Java make a great team.

Nothing, hence my "unless they run on the same VM" comment.

Re: Performance Improvements in .NET 10

#85

C# is definitely fast. There are some benchmark games that I relied on in the past as a quick check and saw it as underwelming vs rust/c++. For example: https://benchmarksgame-team.pages.debian.net/benchmarksgame/... We see that the fastest C# version is 6 times slower than the rust/c++ implementation. But that's super deceiving because those versions use arena allocators. Doing the same (wrote this morning, actually…

You summarise it perfectly. Exactly my thoughts as well.

Imagine if we had something with rust syntax but csharp’s support and memory management trade off with escape hatch

Re: Performance Improvements in .NET 10

#86
post #73

Earlier quoted context omitted.

Efficient memory allocation is part of a well written designed API. Languages like C++ give you a tonne of options here, from passing in scratch buffers to libraries, passing in reusable containers, move semantics, to type erased primitives like std::memory_resource and std::shared_ptr

Perhaps rather than "a tonne of options" people might like to have fewer that are actually good ?

I'd you're using an unmanaged language then you need to think about memory allocation and ownership.

This is something you should think about early on in your design.

Re: Performance Improvements in .NET 10

#87
post #86

Earlier quoted context omitted.

Perhaps rather than "a tonne of options" people might like to have fewer that are actually good ?

I'd you're using an unmanaged language then you need to think about memory allocation and ownership. This is something you should think about early on in your design.

I do think about such things, but having "a tonne of options" when they're mostly terrible is the opposite of helpful.

Let's pull out an easy one, you mention the move assignment semantic. In C++ that's a performance leak because it isn't the destructive move - so each such move incurs a creation whether you wanted one or not and it may also incur a "moved-from" check in the destructor, another overhead you wouldn't pay with the destructive move.

Re: Performance Improvements in .NET 10

#88
post #2

Amazing progress, some LINQ constructions were made 300 times faster. But reasoning over what code does heap allocations is getting more and more complicated. I guess intuition has to give even more way to benchmarking

My view, which I suspect even Toub would agree with is that if being allocation free or even just extremely low allocation is critical to you, then go ahead and use structure and stackalloc, etc that guarentee no allocations.

It is far more guarenteed that that will work in all circumstances than these JIT optimizations, which could have some edge cases where they won't function as expected. If stopwatch allocations were a major concern (as opposed to just feeling like a possible perf bottleneck) then a modern ValueStopwatch struct that consists of two longs (accumulatedDuration, and startTimestamp, which if non-zero means the watch is running) plus calling into the stopwatch static methods is still simple and unambiguous.

But in cases where being low/no allocation is less critical, but your are still concerned about the impacts of the allocations, then these sort of optimizations certainly do help. Plus they even help when you don't really care about allocations, just raw perf, since the optimizations improve raw performance too.

Re: Performance Improvements in .NET 10

#89
post #54

Earlier quoted context omitted.

> It’s the same as other layers we have like auto-vectorization where you don’t know if it’s working without performance analysis. The complexity compounds and reasoning about performance gets harder because the interactions get more complex with abstractions like these. Reasoning about performance is hard as it is, given nondeterministic optimisations by the CPU. Furthermore, a program that's optimal for one impleme…

I enjoy reading your comments here. Thanks for sharing your knowledge, I'll watch the talk. > Yes, and arenas may give such usage patterns a similar CPU/RAM knob to tracing collectors, but this level of control isn't free. In the end you have to ask yourself if what you're gaining is worth the added effort. For me using them has been very easy/convenient. My earlier attempts with Zig used alloc/defer free everywhere…

Sure, using arenas is very often straightforward, but it also very often isn't. For example, say you have a server. It's very natural to have an arena for the duration of some request. But then things could get complicated. Say that in the course of handling the transaction, you need to make multiple outgoing calls to services. They have to be concurrent to keep latency reasonable. Now arenas start posing some challenges. You could use async/coroutine IO to keep everything on the same thread, but that imposes some limitations on what you can do. If you use multiple threads, then either you need to synchronise the arena (which is no longer as efficient) or use "cactus stacks" of arenas and figure out a way to communicate values from the "child" tasks to the parent one, which isn't always simple (and may not even be super efficient).

In lots of common cases, arenas work great; in lots of common cases they don't.

There are also other advantages unrelated to memory management. In this talk by Andrew Kelley (https://youtu.be/f30PceqQWko) he shows how Zig, despite its truly spectacular partial evaluation, still runs into an abstraction/performance tradeoff (when he talks about what should go "above" or "below" the vtable). When you have a really good JIT, as Java does, this tradeoff is gone (instead, you trade off warmup time) as the "runtime knowns" are known at compile time (since compilation is done at runtime).

Re: Performance Improvements in .NET 10

#90
post #3

If only they could fix the ecosystem's stability; I feel like anything written with C#'s staple packages becomes outdated considerably faster than any other options.

I haven't written C# professionally since the early 2010s but back then the language had a big problem in that the old Container classes were not compatible with the Container classes that were added when they added generics to C#. This created an ugly split in the ecosystem because if you were using Container you could not pass it to an old API that expected a Container. Java on the other hand had an implementation…

> This created an ugly split in the ecosystem because if you were using Container you could not pass it to an old API that expected a Container.

Correct me if I'm wrong but allowing this would mean the called api might insert objects wholly unrelated to X. This would break every assumption you make about the container's contents. Why would this ever be allowed or wanted?

Post reply on HN