13 ms·
Performance Improvements in .NET 7
- giancarlostoro 4y agoNative AOT will come with .NET 7 https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/#native-aot https://devblogs.microsoft.com/dotnet/performance_improvemen... > Native AOT is different. It’s an evolution of CoreRT, which itself was an evolution of .NET Native, and it’s entirely free of a JIT. The binary that results from publishing a build is a completely standalone executable in the target platform’s platform-specific file format (e.g. COFF on Windows, ELF on Linux, Mach-O on macOS) with no external dependencies other than ones standard to that platform (e.g. libc). And it’s entirely native: no IL in sight, no JIT, no nothing. All required code is compiled and/or linked in to the executable, including the same GC that’s used with standard .NET apps and services, and a minimal runtime that provides services around threading and the like. Of course it does have some downsides: > It also brings limitations: no JIT means no dynamic loading of arbitrary assemblies (e.g. Assembly.LoadFile) and no reflection emit (e.g. DynamicMethod), everything compiled and linked in to the app means the more functionality that’s used (or might be used) the larger is your deployment, etc. Even with those limitations, for a certain class of application, Native AOT is an incredibly exciting and welcome addition to .NET 7. I wonder how things like ASP .NET will run with Native AOT in the future.
- fabian2k 4y agoI think typical ASP.NET applications likely won't use AOT in the near future. There is quite some "magic" in ASP.NET that I suspect won't work out of the box with AOT because it is heavily reflection-based. And while there are solutions for cases like JSON serialization, as far as I understand they require writing different code right now, so it's not automatic. AOT is much, much more interesting for cases where startup time matters, and ASP.NET usually isn't such a case. But I can imagine that it will be much more useful and easier to implement for smaller, focused tools that don't use that much reflection-based framework code. CLI tools might be the ideal case for trying this out.
- ewjt 4y agoServerless hosting (ie. AWS Lambda) makes ASP.NET a primary use case for AOT because cold startup times cripple performance and increase cost. I suspect they’re just not ready yet and targeting the easy use cases (console apps).
- romanhn 4y agoAs someone writing a .NET-based API hosted on AWS Lambda, I assure you, startup time matters a ton. I spent a bunch of time getting cold start time down to a semi-reasonable number, but there's still a ton of room for improvement. I for one am very much looking forward to progress on AOT Native.
- tmitchel2 4y agoLol snap
- fnord123 4y agoNo, snap startups have an even worse startup time.
- SideburnsOfDoom 4y agoAs someone writing a .NET-based API hosted on AWS Lambda, your case is quite different to a "typical ASP.NET hosted application", that can run for days between restarts.
- ledgerdev 4y agoI would like to host .net based api on google cloud run and azure container apps, which often will go to sleep after about 10 minutes without a request, so cold start time do matter quite a bit. I've done pretty extensive testing and see ~4-7 second cold starts with classic non aot mvc versus ~500ms with natively compiled golang/.net. The reality of the cloud is that sleep & cold starts are very common and in fact necessary to run efficient systems. Half a second is acceptable but 4+ seconds is not and so aot is very important for future apps.
- SideburnsOfDoom 4y ago> I wonder how things like ASP .NET will run with Native AOT in the future. Let me give an example of an ASP.NET app lifecycle: an instance is launched, goes through startup code once. When it reports itself healthy, it is put into the Load balancer and then starts handling requests. Code in these paths is executed anywhere from occasionally to 1000s of times per second. After around 24 hours of this, it is shut down and restarted automatically. So, compiler micro-optimising startup code to take ms off of it, is not interesting at all - it's only run once a day. Startup can take whole seconds, it makes little difference, the instance is ready when it's done. AOT in general isn't that important, but automatic tiered compilation based on usage data is very nice.
- ewjt 4y agoServerless. Running an ASP.NET app in AWS Lambda is just a few lines of code. However, all of a sudden startup time becomes important for both performance and cost. These investments by Microsoft and others[1] allow .NET to remain relevant and viable for modern use cases. [1] https://github.com/awslabs/dotnet-nativeaot-labs https://github.com/awslabs/dotnet-nativeaot-labs
- SideburnsOfDoom 4y agoServerless is great, but if you want to go that route you should be aware that it is in no way a typical hosted ASP.NET app, and while you can "Run an ASP.NET app in AWS Lambda" with little code, there are are better ways to design a Lambda.
- ewjt 4y agoCan you elaborate on “is in no way a typical hosted ASP.NET app”? I get that the machinery under the hood is different (ie. Kestrel web server may not get used). However, we typically don’t care about those details. Our ASP.NET code runs in 3 separate places (containers, servers, Lambda) and the only difference between all 3 is a single entry point file. Do you mean because Lambda is only serving one request at a time and has a more ephemeral host process lifetime?
- pjmlp 4y agoFinally, I always though NGEN was a bad compromise and full AOT should have been supported since .NET 1.0, specially given Delphi's influence.
- geodel 4y agoGood. Java is doing something similar with Graal Native Image thing. In a way it is funny to see few years back so many people were claiming that heavy CPU/memory usage of JIT based platforms would be even more non-issue in Cloud because one can scale as much they need on demand. And now I see AOT/Slimmed Runtime/Compact packaging are happening largely because of cloud deployments. Seems cloud bills are making impact in places where enterprise cloud architects were running amok with everything micro service deployments.
- pjmlp 4y agoActually I think it is more competition pressure of languages like Go and Rust than anything else. I have been using Java and .NET languages for distributed computing for the last two decades, and JIT has always been good enough. By the way, Google rolled back their AOT compiler introduced on Android 5, and since Android 7 it uses a mix of highly optimized interpreter written in Assembly, a JIT compiler with PGO feedback, and when the device is idle, those PGO profiles are used to only AOT compiler the application flows that matter. On more recent Android versions, those PGO profiles are shared across devices via the Playstore. On the .NET front, I think the team has finally decided to make front of the whole C++ rulez of WinDev, specially after Singularity and Midori projects having failed to change their mind.
- geodel 4y agoNowadays Go is working on a PGO solution, so there is that. I don't disagree but kinda doubt that new upstart languages with single digit market and mindshare in enterprise space would force .net /JVM behemoth to do anything. Forget Go, places I work would not know a single new thing beyond Java 1.7 or latest Java 1.8. But they have stood up a dozen cloud teams doing every buzzword you can hear about cloud. So unless finance guys ask tough questions about rising Amazon billing IT wouldn't care if their SpringBoot crapola take 2GB of RAM or 32GB.
- pjmlp 4y agoThe new upstart languages are where the younger generations are, that is why you see .NET doing all those changes to make rolling an Hello World website as easy as doing it in Go, with global usings, single file code, simplified namespaces and naturally AOT.
- ledgerdev 4y agoIt definitely will eventually, probably .net8 timeframe. It will be hard to support so many dynamic features and no doubt will make extensive use of Source Generators. https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/so... Anyone have any interest in a small c# aot micro web framework that cold starts up fast (~500ms, vs ~4s for non aot mvc) on serverless containers like google cloud run?
- davidfowl 4y agoWe've been experimenting with NativeAOT for years with ASP.NET Core (which does runtime code generation all over the place). The most promising prototypes thus far are: - https://github.com/davidfowl/FasterActions https://github.com/davidfowl/FasterActions - https://github.com/davidfowl/uController https://github.com/davidfowl/uController They are source generated version of what ASP.NET does today (in both MVC and minimal APIs). There are some ergonomic challenges with source generators that we'll likely be working through over the coming years so don't expect magic. Also its highly unlikely that ASP.NET Core will not depend on any form of reflection. Luckily, "statically described" reflection generally works fine with NativeAOT. Things like configuration binding, DI, Logging, MVC, JSON serialization all rely on some form of reflection today and it will be non-trivial to remove all of it but we can get pretty far with NativeAOT if we accept some of the constraints. As of right now, we're trying to make sure "motivated people" can play with it, but it's not something that is supported by ASP.NET Core or EF at the moment. https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+nativeaot+is%3Aclosed https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+nativea... PS: Some of the challenges https://github.com/dotnet/aspnetcore/issues/42221 https://github.com/dotnet/aspnetcore/issues/42221
- merb 4y agoActually system text json does work with source generators and di can work with source Generators aswell.
- davidfowl 4y agoThanks for telling me :). On a serious note though, anything can work with source generators but it doesn't match the style of coding that we'd like (moving everything to be declarative isn't the path we want to go down for certain APIs). Also source generators don't compose, so any source generation that we would want to use would need to take advantage of the JSON source generator (if we wanted to keep things NativeAOT safe). Right now most of the APIs you use in ASP.NET Core are imperative and source generators cannot change the callsite so you need to resort to method declarations and attributes everywhere. That's not an optimization, that's a programming model change.
- lvass 4y agoI just can't help laughing profusely whenever I see MS doing a Native something. Don't you folks remember Native HTML5? https://www.youtube.com/watch?v=9mXe9nRiPHI https://www.youtube.com/watch?v=9mXe9nRiPHI
- XzAeRosho 4y agoI don't follow the .NET ecosystem closely enough, but it feels that releasing a mayor version every year feels like kind of unnecessary? Or if they intend to keep doing this, they should release LTS versions of some kind. It feels kind of scary committing to .NET 7 right now, when in a year, it will be replaced by yet another major version promising ever increasing performance gains... Or is the difference between major versions not that big?
- kryptiskt 4y agoEvery other release is an LTS release, with three years of support. .NET 6 was one so this won't be. They are pretty good about backwards compatibility, upgrading .NET Core and .NET hasn't been a big deal so far.
- mikece 4y agoI have an issue with calling three years "long term" support. Most companies won't update to the new LTS for 9 to 12 months in order for any issues to be ironed out, so that means you get only 24 to 27 months on the LTS. Between CVEs and upgrading to dotnet6 before the end of life on dotnet3.1 most of my coworkers and I have gotten almost no new coding done on our applications this summer (and this was after a three month blitz to get all of our code up to dotnet3.1 ahead of the dotnet2.1 end of life less than a year ago). As long as the LTS doesn't introduce a lot of breaking changes then it's not that big of a deal but when you have to refactor and rewrite non-trivial chunks of code this gets to be really wasteful.
- guhidalg 4y agoWhat did you have to rewrite when upgrading from .NET 3.1 to 6? If all you had to touch was ASP.NET startup changes, that's hardly 1 day's worth of work.
- barking_biscuit 4y agoI think this is part of the intent. Letting software get painfully out of date is something that wrecks code bases and companies, yet that's the way they naturally want to operate. Since they've always operated that way they're not use to budgeting for the resource to continually stay up to date. I prefer to upgrade on a regular cadence and even think LTS is an anti-pattern. The regular cadence means upgrades are as small as possible when they do happen, and people experienced with upgrading are more present in the engineering team. The alternative is shit gets 5 years out of date and then 10 years out of date.
- spaetzleesser 4y agoOn the one hand it's cool that they are improving but how do people keep up with all these additions? I find this really hard. Seems a lot of the changes are new stuff which you have to evaluate and see how they could actually be used productively. For example a while ago I tried the new nullable stuff and while in theory it looks straightforward it turned out to be very difficult to use nullable with existing APIs and code in a productive way. The same applies to a lot of the other new features. I feel .NET Core after a good start is falling into the typical Microsoft trap of constantly cranking out new stuff to do the same thing and leaving it to developers to keep up. That's how we ended up with several .NET desktop UI frameworks that are more or less in maintenance mode without a real upgrade path to the currently fashionable framework (which will most likely be abandoned soon too).
- rr888 4y agoI think this is pretty common with a lot of legacy code bases in popular languages. Lots of big systems on Java 8, Python 2, we wont talk about JS. :)
- hardware2win 4y ago>On the one hand it's cool that they are improving but how do people keep up with all these additions? I find this really hard. Very often they improve things in a way that you'll get an improvement regardless of whether you are aware E.g linq, collections, regexes, etc.
- pjmlp 4y agoWe don't really keep up. I read with interest all these articles, and then go back coding our LOB stuff in .NET Framework 4.7.2 and similar. On the Java side, I am finally confident that all our servers have at least Java 11 on them. Only on private stuff do I happen to enjoy latest versions.
- jabart 4y agoNullable's have been around for at least a decade and before .Net core existed? Are you thinking of the NotNull attribute argument checking instead(Likely the wrong term here)? Any change in a data type to an existing API or code will always be tough and a lot of work. Maybe an in32 to a in64 being the exception. Library developers are looking at these and following them to make enhancements. Developers working on business apps get the automatic performance improvements of these changes and the library dev changes to improve performance and allocations. I personally quickly go over these so when I get into a performance issue I have a little bit to know where to go find more information.
- krona 4y agoI wish benchmarks with sample means in the tens of nanoseconds weren't reported and compared by the arithmetic mean. These are not normal distributions and a 10% improvement could just mean you improved the 99% percentile, which is quite typical in my experience given how skewed the distributions tend to be.
- uwuemu 4y ago... that awkward moment when video game tech reviewers like DigitalFoundry provide better benchmarks of video game performance than a tiny company like Microsoft does for its biggest inhouse programming ecosystem.
- kevingadd 4y agoVideo game performance is generally measured in milliseconds, not nanoseconds. The comparison would be if you were benchmarking things like physics sim updates on a per-object basis, or rendering on a per-triangle basis. Those would also be in nanoseconds. As a game dev you're typically operating in terms of things like 'rendering our UI is taking 0.5ms, can we get it lower so we have more time for the terrain?'
- svick 4y agoMany of the benchmarks are using BenchmarkDotNet, so consider reporting this to them: https://github.com/dotnet/BenchmarkDotNet/ https://github.com/dotnet/BenchmarkDotNet/.
- hermitdev 4y agoLooks like the author is explicitly excluding "Error", "StdDev", "Median", "RatioSD" from the ouput. It's in the setup[0]. I'm guessing the author omitted them for brevity. [0] https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/#setup https://devblogs.microsoft.com/dotnet/performance_improvemen... edit: meant "excluding", not "including"
- hardware2win 4y agoDamn Stephens posts exciting as always
- esprehn 4y agoUnfortunately looks like still no compact strings like Java or JS: https://github.com/dotnet/runtime/issues/6612 https://github.com/dotnet/runtime/issues/6612 You can work around it, but it's nice in languages where common text doesn't take double the memory (because of utf8 or compact strings).
- svick 4y agoUTF-8 string literals will be part of C# 11/.Net 7, which could help. But they're still more awkward to use than the UTF-16 string.
- gavinray 4y agoIs this what you're talking about? > "Arguably the biggest improvement around UTF8 in .NET 7 is the new C# 11 support for UTF8 literals." > "UTF8 literals enables the compiler to perform the UTF8 encoding into bytes at compile-time. Rather than writing a normal string, e.g. "hello", a developer simply appends the new u8 suffix onto the string literal, e.g. "hello"u8. At that point, this is no longer a string. Rather, the natural type of this expression is a ReadOnlySpan<byte>. If you write:" > public static ReadOnlySpan<byte> Text => "hello"u8; > public static ReadOnlySpan<byte> Text => new ReadOnlySpan<byte>(new byte[] { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'\0' }, 0, 5);
- esprehn 4y agoNo, not unless you can pass a ReadOnlySpan into every API that expects a String. The change you referenced let's folks work around the fact that String is UTF16. It doesn't transparently handle ASCII with one byte like other languages. See the GitHub issue or https://openjdk.org/jeps/254 https://openjdk.org/jeps/254 The .NET 7 change doesn't retain backwards compatibility
- jsmith45 4y agoDoing magic with the internal string format was considered by the .net team and rejected. There are multiple operations that right now are O(1) no-allocation, that would become sometimes O(n) allocating if they did that sort of magic. This includes: PINVOKEing windows APIs that are expecting WCHARS, converting a string to a ReadOnlySpan<char>, and using `unsafe` to pin a string and access its contents as a `char*`. Making code that users may have been relying on being O(1) and non-allocating into possibly O(n) and allocating was deemed too disruptive. Plus because strings store their contents within themselves, the on-demand conversion of a string to UTF-16 would require allocating a new object, and updating all pointers to the old object to refer to the new one. Which currently is an operation only done by the garbage collector. If expanding the string on-demand required running a full garbage collection to handle this... yeah, going from O(1) non-allocating, to o(n)+Full Garbage Collection is a total non-starter. I think Java on the other hand did not expose very many places where a string could be observed to be a utf-16 character array under the hood (perhaps only as part of JNI marshaling?) making the ascii-only string optimization more feasible. Javascript never made the strings internal encoding visible, simply requiring that the indexer be able to return a UTF-16 value in O(1), so the ASCII optimization is simple there.
- fabian2k 4y agohttps://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/#json https://devblogs.microsoft.com/dotnet/performance_improvemen... This is a really interesting, or rather terrifying part of that blog post. I thought I had a reasonably good knowledge about typical performance mistakes in .NET, but I never heard about this particular one. If I understand it right, initializing a fresh JsonSerializerOptions object before each call to Serialize/Deserialize in System.Text.Json is incredibly expensive. It essentially disables the cache and means the serializer analyzes this case fully every time. And this is more on the order of 100x as expensive than using the cached version, so not a trivial amount.
- kevingadd 4y agoA polite way to describe most serialization tooling in the .NET ecosystem would be "bad". It's unfortunate, but it's good to see improvements happening. I still try to avoid JSON in general on .NET since I've had so many bad experiences with the various JSON libraries out there. Sadly if you want to ship well-performing software in .NET it's still mandatory to run it under a profiler on a regular basis, both to spot frequent unnecessary GC allocations and to spot CPU bottlenecks. Either one would probably catch this particular problem, thankfully! I use the built in VS profilers sometimes, and other times I use Superluminal's excellent CPU profiling.
- aliswe 4y agoStreaming serialization with System.Text.Json doe.
- neonsunset 4y agoMost pitfalls in .NET are luckily along the lines of "punishing people who redo all the steps on each method call or write code Java style" which might even be a good thing. I wonder where does your bad experience with Json libraries come from? Even back in the days of .NET Framework, there was a variety of quality libraries such as Newtonsoft.JSON, Utf8Json or other more interesting but less feature-rich packages. Nowadays, STJ provides quite good defaults and in places where they differ from Newtonsoft, there usually is a reason for that. I'm not saying all APIs are successful, namely, I consider OOB API for source generated serialization to be really user-unfriendly. However, other than that, just don't do unnecessary work and cache stateless objects like serializer settings. This translates to most programming languages and isn't something C# specific.
- rkagerer 4y agoThat blog site could use some performance enhancements. Anyone have a link to a static copy?
- throwaway_au_1 4y agoFor me, the Feedback button anchored to the viewport right does not work, and I'm not interested in signing up to leave a comment on the page, but in the event the author or anyone associated with them stumbles across this: This article reliably causes Chrome to hang on my Samsung Android. No suggestions re. the length here, just feedback.
- rkagerer 4y agoYeah it hung my Chrome on Samsung Android consistently. Firefox on Android pulled it up smoothly.
- jackmott42 4y agoFor people curious how much impact the .NET performance improvements over the last 5 years have on real, large scale web applications: At work we have a core piece of our online ordering system that has been running on .NET Framework 4.8. We run around 8 web servers and handle around 4,000 orders per minute, 300 requests per second per server. We have been working on porting everything over to .NET 6 by making all the code compatible so we can build both from the same code base, and we just started putting the .NET 6 version live on one of the webservers for a few hours at a time to test it out. CPU usage on that .NET 6 machine is 1/2 of the Framework machines! Impressive improvement, and .NET 7 should be even better.
- pwdisswordfish0 4y ago"Framework" is such a poor differentiator to contrast with modern .NET (owing to the original poor naming decision in the first place--it's not like ".NET" itself is amazing) that it's hard, from a casual reading, to pick up on the fact that "Framework" is even being used a differentiator. I propose that when people want to differentiate between the modern .NET Core vs the legacy closed source .NET implementation, the latter is referred to as "OG" .NET (in casual and business-casual contexts, at least).
- whoisthemachine 4y agoA suggestion I liked was to call ".Net Framework" ".Net classic" a la "ASP classic", nicely honors the original .Net while properly suggesting it is not the "new" .Net.
- wombarly 4y agoPlease, no more name changes.
- pwdisswordfish0 4y agoNot a name change, just an editorial prescription for discussions. The proper name is .NET Framework (just don't call it that!).
- devmunchies 4y ago> A huge amount of effort in .NET 7 went into making code gen for Arm64 as good or better than its x64 counterpart Awesome. I was using an LSP server for F# (in Sublime Text) on an M2 Mac and it was always running at 500%+ CPU. I had to turn off the LSP server. Hopefully this version fixes it.
- chusk3 4y agoAssuming you're talking about FsAutoComplete and this was recently, that's nothing to do with the .NET Runtime and entirely a coding mistake that I made that we've released a fix for :)
- devmunchies 4y agoOh! HAHA it was FsAutoComplete. right on. Thank you!
- noveltyaccount 4y agoThis is the most Hacker News comment I have ever seen, lol. The actual guy behind the bug here replying to comments with a mea culpa :D
- deleted 4y ago[deleted]
- nimish 4y agoInteresting that branch was chosen over CMOV in the ToString bool case, it's a PGO case study: https://discourse.llvm.org/t/rfc-cmov-vs-branch-optimization/6040 https://discourse.llvm.org/t/rfc-cmov-vs-branch-optimization...
- mastax 4y agoThere was a (very long) post recently talking about the Regex performance improvements in .NET 7[0]. It's comprehensive and well written and I found it very interesting. I love the new Regex source generator not just because of the performance but because you can step into the C# code and understand pretty well what the regex is doing. [0]: https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7 https://devblogs.microsoft.com/dotnet/regular-expression-imp...
- Mindless2112 4y ago> try running Console.WriteLine((object)new uint[42] is int[]);, and you’ll find it prints out True I knew .NET's array variance rules were kinda bad, but that's really surprising.
- effnorwood 4y ago
- fomine3 4y agoAs always, it's impressing that a single person can write this post.
- jmnicolas 4y agoI wonder why Mono still exists, I thought they would merge it in coreclr.