Ah the traditional browser stress test from the .NET team. :)
Joke aside, yet another interesting read of all little improvements that go across all the runtime, and very much appreciated that they put out the effort to go through this detail level.
I noticed that audio quality begins degrading above 100% (at least if the media is already at high volume), so it really is a useful concept. I'm unsure what Linux distro I'm recalling this from, but it was useful on my little old netbook from college
The software has to start clipping the audio above "100%", but I use it regularly in say, VLC, because I might want the volume slightly higher without increasing my whole system volume just to hear a quiet section. I rarely notice any degradation at 150%.
> The sections that follow are full of real improvements. A bounds check removed, an allocation that no longer happens,
Annoyingly the.net blog seems to have started to use LLMs to write their copy. Using "real" twice in one paragraph - do LLMs do that? Lots of commas is a tell for me.
> This is a long one. It’s meant to be. Grab your hot beverage of choice, settle in, and let’s turn it up.
I suspect it was done old school: Written by Stephen and passed to a LLM to fill in all those links and other garnish and then passed back for final polish by Stephen. That's how I do my write ups (but generally without the LLM bit for shorter efforts).
This is a long write up, and I'm sure it will have been assisted, but in the right way, and not a sloppy way.
I've dropped several commas before conjunctions, soz!
FWIW the .NET 10 release also had 2 occurrences of "real" in literally the first paragraph.
I, too, tire of the constant YOU WROTE THIS WITH LLMs outrage. An incredible engineer dumped an ENORMOUS amount of technical knowledge at your feet, and you're commenting on the smell? Is that all you have to contribute?
I saw this too on the Ryan Carniato/SolidJS 2.0 announcement post. A world-class engineer makes a great blog post, and all the comments can focus on are the LLM-smells. Oh well. Any reason not to learn, I guess.
You don’t need to, but if you ever want to really optimise some code, understanding what it turns into on the target CPU really helps. Especially if you know the implications for any particular instruction (cost of memory access, branch prediction misses, etc)
Most devs won’t ever need to know this stuff, but as someone who grew up with computers that could barely do anything without grinding to a halt (8bit computer, 2mhz processor, 32kb of RAM, 20kb of which is for the screen), I still find this stuff useful.
Not really, you only need to know you can get at it. One day you might be doing something like processing images or video and you are finding it slow and getting down to this level can be helpful. But it wouldn't necessarily be the first thing you'd look at.
Kinda. I use the `disassemble` function in Common Lisp quite a bit, and I can't work backwards to explain what a function is doing based on the disassembly.
BUT what I can do is see which functions are being inlined, which values are in memory versus in registers, see if things are being boxed and unboxed a lot, see if SIMD is being used, etc.
And more importantly I can compare two versions of a function to see which one looks better by those criteria. It's not perfect, but IME it works really well for guiding optimization.
What I wish more languages did was what the guile optimizer does. There is a source->source optimizer which does inlining, DCE, CSE and partial evaluation.
That is very handy, especially when writing macros. I only have to look at assembly when I want to know about optimizations that are not visible in the source->source optimizer.
If I ever want to know if something is reified (which I never do) I can always look at the ASM.
Assembly is honestly very easy to learn, especially ARM assembly, for the basics (even if whole-program assembly is still difficult). In the worst case, you end up learning something interesting.
Yes. Every professional programmer should be able to read assembly. This culture of ignorance that has been fostered, as seen in sibling comments, is why Notepad now takes 10x as much memory as a full operating system like Windows 95. Application developers should absolutely have an idea of how not to piss away their users' resources. Understanding what you're abstracting away is crucial to that. I promise you it's not even hard. In the 90s every professional programmer understood assembly. It was normal, not some elite hacker language. It can still be normal.
C# takes a lot of different roles. If all you're doing is higher level stuff, say you're only working on a local GUI app where you're waiting on the user 99% of the time, you probably don't need to understand it. But you can also treat C# as more of a low level systems language, maybe you need to optimise some number crunching in a server - and then, as with any systems language, being able to read it may help.
AoT uses the same codegen (mostly) as the JIT so if you see a JIT improvement it's possible NativeAOT/ilc picked up that improvement too.
Unless it's a runtime-only optimization, like guarded devirtualization... there's no straightforward way for an AOT compiler to do that without profiling data.
Native AOT is seeing a lot of use within Microsoft products too. Some bits of the .NET SDK use it, and C# Dev Kit (the C# extension for VS Code) uses it extensively in version 11. It brings a lot of performance to .NET.
Flip side: LLMs have to be very explicitly told to code in "modern" .NET and C# due to lack of representation in the training set.
Case in point: extension members from C# 14 is one that LLMs commonly stumble on and requires an explicit example. It still sometimes says that this is not valid syntax.
extension(SomeType instance)
{
public OtherType DoSomething() { ... }
}
Agents really struggle on this one for some reason.
Even older releases have a few that I notice LLMs making mistakes on like use of `System.Threading.Lock` over `Object` when locking.
I wonder if any of those work alongside Github Copilot (the autocomplete not actual agent).
Because at this point I would do anything if I could get Github Copilot to understand the new language features and stop trying to constantly revert code.
The one specific thing I'm constantly having to deny is Copilot seeing this:
Buildings games in Unity feels like magic with frontier reasoning models.
Assuming you are competent with scene work and the various art pipelines, the rest of the problem is significantly easier now.
I've been using the Unity CLI to run arbitrary C# code against Unity 6 scenes without requiring domain reloads. It uses Roslyn to compile the snippet in a special Unity editor component instead of running the normal compilation pipeline.
The implications for a reasoning model are significant. Domain reloads in my projects can take 10-20 seconds. Compound across 5-10 tool calls and the difference adds up very quickly.
Very thorough write up. Clearly a lot of performance improvements across their stack. As if it wasn't detailed/long enough already, I would have loved to see some application-level benchmarks that gave a hint of the cumulative performance gains we should expect.
Too bad there’s such a lingering culture of Windows and creaky Lenovos and Dells around it. I’m sure it can be different, but I’m not taking my chances ever again. Simply not worth my sanity.
We've banned this account for repeatedly posting abusive comments and ignoring our appeals to stop. If you don't want to be banned, you can email us and demonstrate an intention to observe the guidelines. https://news.ycombinator.com/newsguidelines.html
Not sure when your last foray into the .NET ecosystem was, but every since it is xplat and unified (.NET 5 probably) it is a real joy. I use VSCode as IDE for C# on my mac, and deploy to Linux.
He didn't say you can't use Linux or MacOS, he said there's still a culture of being Windows and Microsoft only across .NET shops. As an ex .NET dev I can confirm, the community is quite close minded, language is awesome.
I've been using .NET almost exclusively on Linux since it was called .NET Core 2.0, and development platforms other than Windows do feel like second class citizens. Any time you venture into anything remotely advanced, the tooling is usually Windows only.
"Everything" expects you to use MSSQL, even if today there's ok official support for PostgreSQL and SQLite. Most "thought leaders" of various sorts are on Windows and expect you to use it. This pervades throughout the ecosystem.
Can't see this ever changing as it's not in MS' interest to turn other operating systems into good .NET development platforms.
I'm sure you know more about this than me, but EF works fine with SQLite for a project I work on. There are limitations, but I think there's a difference between the idea of EF deliberately not implementing some features for SQLite and SQLite itself not having support for some EF features (which is the reality I'm familiar with).
SQL Server is the flagship database project on the Microsoft side and that team surely has some imperative to facilitate the EF vision. It simply must be less of a priority for the PostgreSQL and SQLite maintainers to do so. Is that really a valid dig on the .net ecosystem, though?
Incidentally, I'm seriously considering dropping EF. The ability to apply migrations is nice. I find the means of authoring them to be arcane and capricious. Not having to write every simple query is nice, but it gets really hard to do complex or high performance stuff. After a decade of using this thing, I find myself fighting the Entity tracker more and more and now I'm seriously questioning if it's really all worth it.
I use EF now - but only for the string interpolation in Database.SqlQuery and Database.ExecuteSql. We don't use POCOs but instead use XML and JSON with Linq.
It's really the navigations that make EF a problem. I've built a typed graph database on top of Sqlite that works really well specifically because it's in Sqlite, so the overhead of the 1+N query problem with recursively descending navigations isn't a big problem. But it requires lazy loading and that requires all the navigation to happen inside a single service scope and that makes sequencing some things get difficult (can't just pass the results around willy nilly).
To be fair, in EFcore (other than EF) lazy-loading and auto-navigation is not on by default - you opted in at some point (with all its trade-offs). EFcore differs from traditional EF that they removed a lot of the magic or made it opt-in, and you can use EFcore as a very basic/thin query engine similar to Dapper.
I can't even remember the last time I used MSSQL with .NET. I'm embarrassed that I worked on projects now that were paying huge sums for licenses when .NET works so absolutely well with every other DB.
These days I just use EF with Sqlite on 99% of my projects.
I used .NET for many years with Postgres on a huge project. Honestly, I don't know what you mean. Can you break down "Everything" a little. What is it that expects MSSQL? Who are the thought leaders pushing it?
I'd say Microsoft's revenue related push with .NET these days is to try to subtly nudge you into Azure (where MSSQL is rare and Windows is virtually non-existent).
But, I also think they know they will kill .NET if they go overboard with it as the competition is strong.
I do all my dev in .NET on a mac, using Postgres and Sqlite only, so I don't relate to your experience at all. It's dead simple for me and I'm not even that good of a developer.
That is not my experience. Sure, the background of .NET is windows, but in the last decade or so it opened up to other platforms, and so many shops prefer deploying their .NET based applications to linux for multitude of reasons. Along with this comes linux oriented culture.
So windows culture is not tied to .NET per se, more so tied to certain shops I would say.
Speaking from anecdotal experience, I have no numbers on this :)
It is different. I do nearly 100% of my .NET development on macOS, only dropping into Windows to support .NET Framework users of open-source projects I work on, and we deploy exclusively now on Linux containers. The apps I maintain haven't touched a Windows server in years. My colleagues (and OSS co-maintainers) use a mix of macOS, Windows, and Linux. I use Rider instead of Visual Studio.
The only time I've been forced into a "culture of Windows and creaky Lenovos and Dells" recently was on a Java project. (Anecdotally, of course. Java has a similarly cross-platform culture as a whole.)
I do .NET dev exclusively on a mac completely within Visual Studio Code and it's by far the easiest and most enjoyable framework and ecosystem I've had the pleasure of working in. I couldn't be happier with it.
Now if only they could spend time making Visual Studio 2026 perform up to par.
Just today I created e.g. 100 changes in a file, performed an undo and it rolled back 90 or so of the changes while somehow managing to keep the 5 at the start and the 5 at the end.
The writing style is similar to the other articles by the same author. He has been doing this for years. I have no idea what your problem with the actual content is.
I've been reading these since the .NET 5 performance improvements blogpost. Again, the content is ever-sharp but the style is so full of claudisms it's next to unbearable to read. I'm not anti-AI by any means, I just find it annoying, that's it really.
Agree. A whole tree of comments agreeing with you is not appearing on this post because that's how HN works.
I loathe LLM prose, no matter who posts it.
My prizes for spending the internet points to say this are the joy of resisting normalization of illiteracy and a tacit camaraderie with the hundreds of others who agree but won't comment or upvote.
For anyone who enjoys Stephen Toub’s deep technical articles like this one as much as I do - he also published another post today on migrating the Copilot coding harness from Node.js to Rust. Another great read.
`AsyncMethodBuilder` is a way to declare async methods that return your own task types. AFAIK it is not supported with the current runtime async, and maybe never will be - it's quite hard to support, I believe.
actually this is likely just as performant as the "Ugly but fast" code from the famous talk. After all, this is just branching on GetType() == typeof(Dog) which is presumably boiling down to an integer comparison. This roughly the same as the following C code:
void speak_generic(void* animal, int type_id) {
if (type_id == DOG) {
dog_speak((Dog*)animal);
} else {
dispatch_speak_vtable(animal);
}
}
Advantage 1:
You don't have to maintain this logic (its automatic), so you won't get weird cases if you forget to update all your switches everywhere, and/or you get weird fallthrough logic and footgun yourself in C.
Advantage 2:
You still get the flexibility of the vtable if you need it (for the case the type is chosen at runtime at not known). But for 90% of cases, its just as fast as the ugly C code.
Disadvantage 1: Losing a smug sense of superiority because you eschew abstractions and prefer writing verbose error-prone switch statements over clean easy to understand code.
You can always just not use OOP. C#'s tooling for functional programming and C-style programming is really good, thanks to stuff like statics on interfaces or spans.
Outside of the outstanding optimizations .net has made (plus async runtime), what I really enjoyed was the reworked entry section. Stephen reiterated all the concepts from the past Performance Improvement articles to really showcase the layers of optimization techniques and how the can transform.
- "how much things they postpone to put into v11 ?"
- "moving to stack is faster then heap"
- so.. why they just not use multiple stacks ?? ring buffers are just progressive stack but plain stack is just pointer moving... Hmm, but what is usecase except recursive function calling ?
- ok, I read that articele
- what ? it's just a first part ??
- async thingies
- "state machines looks like that"
- aha, always wanted to konw that, thank you Microsoft! Wait, what?? What I just said ?? That really happened?
- scroll, then scroll more some asm code, maybe I read it later
- something interesting, don't remeber now
- next morning coffee time: O, I have some more to read, maybe I can learn something more ?
- ok, work time but probably will finish reading later today
So it is realy nice article. I learned how to do old-school async wrappers in plain C :)
I remember .NET fails when there were dramas about not open sourced debugger, planning to remove hot reload (make it only available in Visual Studio because of licensing) or poor support in Visual Studio Code compared to other languages. AFAIK many people were angry that VS Code is not first class editor for C#/.NET. I am not sure how it is these days.
https://isdotnetopen.com/ has a good list of "dramas" questioning if .NET is truly open. At least there are not many new dramas from Microsoft...
For me it's not that big of a deal that some parts are not open. At least we have good competition (Microsoft (Visual Studio, VsCode c# Dev Kit) vs Jetbrais (Rider, VsCode + recent "Resharper for VsCode" extension.) that prevents one party to mess up something big.
C# Dev Kit is also receiving huge performance improvements with .NET 11. It's available now on the pre-release version of the extension, if you want to check it out. Some details in the .NET Unboxed video here https://m.youtube.com/watch?v=5fvi7m1QxIY
111 comments
[ 9.8 ms ] story [ 152 ms ] threadJoke aside, yet another interesting read of all little improvements that go across all the runtime, and very much appreciated that they put out the effort to go through this detail level.
I can wind it up to 15! \||/ (is there an official ASCII art four finger devil's horns)
Annoyingly the.net blog seems to have started to use LLMs to write their copy. Using "real" twice in one paragraph - do LLMs do that? Lots of commas is a tell for me.
> This is a long one. It’s meant to be. Grab your hot beverage of choice, settle in, and let’s turn it up.
Ugh.
I suspect it was done old school: Written by Stephen and passed to a LLM to fill in all those links and other garnish and then passed back for final polish by Stephen. That's how I do my write ups (but generally without the LLM bit for shorter efforts).
This is a long write up, and I'm sure it will have been assisted, but in the right way, and not a sloppy way.
I've dropped several commas before conjunctions, soz!
I, too, tire of the constant YOU WROTE THIS WITH LLMs outrage. An incredible engineer dumped an ENORMOUS amount of technical knowledge at your feet, and you're commenting on the smell? Is that all you have to contribute?
I saw this too on the Ryan Carniato/SolidJS 2.0 announcement post. A world-class engineer makes a great blog post, and all the comments can focus on are the LLM-smells. Oh well. Any reason not to learn, I guess.
Most devs won’t ever need to know this stuff, but as someone who grew up with computers that could barely do anything without grinding to a halt (8bit computer, 2mhz processor, 32kb of RAM, 20kb of which is for the screen), I still find this stuff useful.
But I am a bit of a performance tuning nerd, so..
Usually. BRK is a breakpoint.
(Also, other architectures might use J for 'Jump' rather than 'Branch'). I don't make the rules ;)
BUT what I can do is see which functions are being inlined, which values are in memory versus in registers, see if things are being boxed and unboxed a lot, see if SIMD is being used, etc.
And more importantly I can compare two versions of a function to see which one looks better by those criteria. It's not perfect, but IME it works really well for guiding optimization.
That is very handy, especially when writing macros. I only have to look at assembly when I want to know about optimizations that are not visible in the source->source optimizer.
If I ever want to know if something is reified (which I never do) I can always look at the ASM.
You should learn assembly anyway, but it won't make this part any more insightful.
Unless it's a runtime-only optimization, like guarded devirtualization... there's no straightforward way for an AOT compiler to do that without profiling data.
Case in point: extension members from C# 14 is one that LLMs commonly stumble on and requires an explicit example. It still sometimes says that this is not valid syntax.
Agents really struggle on this one for some reason.Even older releases have a few that I notice LLMs making mistakes on like use of `System.Threading.Lock` over `Object` when locking.
Because at this point I would do anything if I could get Github Copilot to understand the new language features and stop trying to constantly revert code.
The one specific thing I'm constantly having to deny is Copilot seeing this:
into this:Assuming you are competent with scene work and the various art pipelines, the rest of the problem is significantly easier now.
I've been using the Unity CLI to run arbitrary C# code against Unity 6 scenes without requiring domain reloads. It uses Roslyn to compile the snippet in a special Unity editor component instead of running the normal compilation pipeline.
The implications for a reasoning model are significant. Domain reloads in my projects can take 10-20 seconds. Compound across 5-10 tool calls and the difference adds up very quickly.
I'd be interested in hearing more.
The community is being diluted by…a different demographic!
Just curious.. what language(s) are you using now?
"Everything" expects you to use MSSQL, even if today there's ok official support for PostgreSQL and SQLite. Most "thought leaders" of various sorts are on Windows and expect you to use it. This pervades throughout the ecosystem.
Can't see this ever changing as it's not in MS' interest to turn other operating systems into good .NET development platforms.
SQL Server is the flagship database project on the Microsoft side and that team surely has some imperative to facilitate the EF vision. It simply must be less of a priority for the PostgreSQL and SQLite maintainers to do so. Is that really a valid dig on the .net ecosystem, though?
These days I just use EF with Sqlite on 99% of my projects.
I'd say Microsoft's revenue related push with .NET these days is to try to subtly nudge you into Azure (where MSSQL is rare and Windows is virtually non-existent). But, I also think they know they will kill .NET if they go overboard with it as the competition is strong.
The only time I've been forced into a "culture of Windows and creaky Lenovos and Dells" recently was on a Java project. (Anecdotally, of course. Java has a similarly cross-platform culture as a whole.)
Just today I created e.g. 100 changes in a file, performed an undo and it rolled back 90 or so of the changes while somehow managing to keep the 5 at the start and the 5 at the end.
I’m afraid posts like this might become fleeting.
the technical parts are fresh as ever but the writing style is awful, man
I loathe LLM prose, no matter who posts it.
My prizes for spending the internet points to say this are the joy of resisting normalization of illiteracy and a tacit camaraderie with the hundreds of others who agree but won't comment or upvote.
I don't know if it's even possible anymore to write a detailed, technical article without a swarm of people showing this reaction.
https://github.blog/ai-and-ml/generative-ai/migrating-the-gi...
Here is the "Runtime async" section: https://devblogs.microsoft.com/dotnet/performance-improvemen...
I'm not sure if this will surface as an "enabled by default" feature in .NET 11, but it is an active area of work that will arrive sooner or later.
Advantage 2: You still get the flexibility of the vtable if you need it (for the case the type is chosen at runtime at not known). But for 90% of cases, its just as fast as the ugly C code.
Disadvantage 1: Losing a smug sense of superiority because you eschew abstractions and prefer writing verbose error-prone switch statements over clean easy to understand code.
My reading was like this:
- "how much things they postpone to put into v11 ?"
- "moving to stack is faster then heap"
- so.. why they just not use multiple stacks ?? ring buffers are just progressive stack but plain stack is just pointer moving... Hmm, but what is usecase except recursive function calling ?
- ok, I read that articele
- what ? it's just a first part ??
- async thingies
- "state machines looks like that"
- aha, always wanted to konw that, thank you Microsoft! Wait, what?? What I just said ?? That really happened?
- scroll, then scroll more some asm code, maybe I read it later
- something interesting, don't remeber now
- next morning coffee time: O, I have some more to read, maybe I can learn something more ?
- ok, work time but probably will finish reading later today
So it is realy nice article. I learned how to do old-school async wrappers in plain C :)
https://isdotnetopen.com/ has a good list of "dramas" questioning if .NET is truly open. At least there are not many new dramas from Microsoft...
For me it's not that big of a deal that some parts are not open. At least we have good competition (Microsoft (Visual Studio, VsCode c# Dev Kit) vs Jetbrais (Rider, VsCode + recent "Resharper for VsCode" extension.) that prevents one party to mess up something big.