- by x32x01 ||
.NET 11 brings a large set of performance improvements across the runtime, JIT, libraries, garbage collector, async execution, networking, JSON, LINQ, I/O, and more.
The most interesting change is Runtime Async, which moves part of the
Microsoft's latest performance deep dive covers hundreds of changes in .NET 11, with a strong focus on making generated code smaller, reducing allocations, removing unnecessary bounds checks, improving vectorization, and lowering runtime overhead.
.NET 11 introduces Runtime Async, where the compiler emits a smaller async-aware representation and the runtime and JIT perform more of the transformation.
The important idea is simple:
More of the async implementation is handled at runtime, where the JIT has more information available for optimization.
The C# programming model does not change. You still write normal:
The change happens underneath your application.
With Runtime Async, the runtime can understand relationships between async calls and avoid creating intermediate objects when they are not actually observable or necessary.
The benchmark reported:
Even when the operation actually suspends, the runtime version was substantially faster and allocated less memory.
This does not mean every async operation becomes allocation-free. If a
The optimization is mainly about avoiding intermediate work that exists only because of the previous implementation.
Microsoft compared a small application containing ten async methods:
In that example, the runtime-async version was roughly half the size of the compiler-lowered version.
This can be particularly interesting for applications containing many small async helper methods.
Instead of flattening your code just to avoid potential async overhead, .NET 11 is increasingly able to optimize those layers underneath the source code.
.NET 11 includes improvements that allow the JIT to reuse information it has already established about array indexes, lengths, spans, and index-from-end expressions.
For example, after proving that an array access is safe, later accesses using the same information may no longer require another bounds check.
This matters because bounds checks are small individually, but they can become noticeable inside hot loops and frequently executed code.
Microsoft also reports improvements in areas such as:
The runtime also includes improvements around garbage collection, trimming, compaction, allocations, and memory usage.
Reducing allocations is especially important for server applications because every unnecessary allocation can eventually create additional GC work.
The goal is not simply to make individual operations faster. It is also to reduce the amount of temporary work the runtime has to clean up later.
Microsoft reports changes that reduce unnecessary coordination overhead in some synchronization paths and improve thread-pool behavior.
There is also a new analyzer,
Instead of:
Microsoft recommends using
The analyzer helps identify cases where the original pattern can leave a timer and associated resources pending after the main operation has already completed.
For example, Microsoft reports improvements in
In one benchmark involving concurrent process output reading, the measured time dropped from 587.8 ms on .NET 10 to 541.8 ms on .NET 11.
These changes are important because applications often spend more time moving data between services, files, processes, and the operating system than developers expect.
Even small reductions in per-operation overhead can become significant at scale.
.NET 11 includes improvements across many parts of the standard libraries, including:
That means the performance story of .NET 11 is broader than simply making the JIT faster.
A significant amount of work is happening directly inside the APIs and libraries developers use every day.
The runtime and JIT can optimize existing code more effectively.
For async applications in particular:
It is the direction of the runtime.
The .NET team is moving more optimization work toward a point where the runtime and JIT have enough information to understand what the application is actually doing instead of optimizing only the already-transformed output produced by the compiler.
Runtime Async is a good example of that approach.
Combined with better bounds-check elimination, fewer allocations, improved vectorization, GC changes, threading improvements, and faster library implementations, .NET 11 continues to push performance improvements deeper into the platform.
For developers building high-throughput APIs, services, networking applications, or other performance-sensitive workloads, these low-level changes can matter even when the application source code barely changes.
The most interesting change is Runtime Async, which moves part of the
async/await transformation from the C# compiler into the .NET runtime and JIT. This gives the runtime more information at optimization time and can eliminate work that was previously required at each async boundary.Microsoft's latest performance deep dive covers hundreds of changes in .NET 11, with a strong focus on making generated code smaller, reducing allocations, removing unnecessary bounds checks, improving vectorization, and lowering runtime overhead.
⚡ Runtime Async: A Major Change in async/await
Traditionally, the C# compiler transforms anasync method into a state machine containing generated code such as MoveNext, state fields, and an async method builder..NET 11 introduces Runtime Async, where the compiler emits a smaller async-aware representation and the runtime and JIT perform more of the transformation.
The important idea is simple:
More of the async implementation is handled at runtime, where the JIT has more information available for optimization.
The C# programming model does not change. You still write normal:
C#:
async Task GetValueAsync()
{
return await GetDataAsync();
} With Runtime Async, the runtime can understand relationships between async calls and avoid creating intermediate objects when they are not actually observable or necessary.
🚀 The performance difference
Microsoft's benchmark shows a two-layer async call chain where the synchronously completing path becomes more than 3× faster with Runtime Async.The benchmark reported:
Code:
ClassicCompleted | 21.221 ns | 144 B allocated
RuntimeCompleted | 6.151 ns | 0 B allocated This does not mean every async operation becomes allocation-free. If a
Task needs to exist as an observable object, it still needs to be created.The optimization is mainly about avoiding intermediate work that exists only because of the previous implementation.
📦 Smaller Async Code and Binaries
Moving more of the transformation into the runtime also reduces the amount of generated code.Microsoft compared a small application containing ten async methods:
Code:
Compiler | 10,752 bytes
Runtime Async | 5,632 bytes This can be particularly interesting for applications containing many small async helper methods.
Instead of flattening your code just to avoid potential async overhead, .NET 11 is increasingly able to optimize those layers underneath the source code.
🧠 JIT Improvements and Fewer Bounds Checks
The JIT continues to become better at proving when runtime checks are unnecessary..NET 11 includes improvements that allow the JIT to reuse information it has already established about array indexes, lengths, spans, and index-from-end expressions.
For example, after proving that an array access is safe, later accesses using the same information may no longer require another bounds check.
This matters because bounds checks are small individually, but they can become noticeable inside hot loops and frequently executed code.
Microsoft also reports improvements in areas such as:
- Bounds-check elimination
- Assertion propagation
- Simplification
- Better constant and range analysis
- Vectorization
- Fewer generated instructions
🗑️ Garbage Collection and Memory Efficiency
Performance work in .NET 11 is not limited to CPU instructions.The runtime also includes improvements around garbage collection, trimming, compaction, allocations, and memory usage.
Reducing allocations is especially important for server applications because every unnecessary allocation can eventually create additional GC work.
The goal is not simply to make individual operations faster. It is also to reduce the amount of temporary work the runtime has to clean up later.
🔄 Better Threading and Task Performance
.NET 11 also contains improvements around threading and synchronization.Microsoft reports changes that reduce unnecessary coordination overhead in some synchronization paths and improve thread-pool behavior.
There is also a new analyzer,
CA2027, designed to detect a common inefficient timeout pattern involving Task.Delay.Instead of:
C#:
if (await Task.WhenAny(someTask, Task.Delay(timeout)) != someTask)
{
throw new TimeoutException();
} Task.WaitAsync for this scenario: C#:
await someTask.WaitAsync(timeout); 🌐 Networking and I/O Improvements
.NET 11 also improves several networking and I/O paths.For example, Microsoft reports improvements in
SocketsHttpHandler and multipart HTTP content handling.In one benchmark involving concurrent process output reading, the measured time dropped from 587.8 ms on .NET 10 to 541.8 ms on .NET 11.
These changes are important because applications often spend more time moving data between services, files, processes, and the operating system than developers expect.
Even small reductions in per-operation overhead can become significant at scale.
📚 Libraries, LINQ, JSON, and Cryptography
The performance work extends well beyond the runtime..NET 11 includes improvements across many parts of the standard libraries, including:
- Collections
- LINQ
- JSON
- Cryptography
- Networking
- I/O
- Numeric processing
- Regular expressions
- Diagnostics
System.Text.Json, full outer joins in LINQ, and X25519 key agreement support in cryptography.That means the performance story of .NET 11 is broader than simply making the JIT faster.
A significant amount of work is happening directly inside the APIs and libraries developers use every day.
🔬 What Does This Mean for Developers?
For most developers, the biggest advantage is that you do not need to rewrite your application to benefit from many of these improvements.The runtime and JIT can optimize existing code more effectively.
For async applications in particular:
- Keep using
async/awaitwhen it makes the code clearer. - Use
Taskby default when it fits your API. - Use
ValueTaskwhen its specific performance and API tradeoffs make sense. - Avoid restructuring clean code solely to work around an implementation detail.
- Benchmark important workloads instead of assuming an optimization will help every scenario.
runtime-async=on feature switch. Microsoft's goal is for the feature to eventually become the default, but developers should measure their own workloads when experimenting with it.🎯 The Bigger Picture
The most interesting part of .NET 11 is not a single benchmark number.It is the direction of the runtime.
The .NET team is moving more optimization work toward a point where the runtime and JIT have enough information to understand what the application is actually doing instead of optimizing only the already-transformed output produced by the compiler.
Runtime Async is a good example of that approach.
Combined with better bounds-check elimination, fewer allocations, improved vectorization, GC changes, threading improvements, and faster library implementations, .NET 11 continues to push performance improvements deeper into the platform.
For developers building high-throughput APIs, services, networking applications, or other performance-sensitive workloads, these low-level changes can matter even when the application source code barely changes.
❓ Frequently Asked Questions
----------------------What is Runtime Async in .NET 11?
Runtime Async moves part of the traditionalasync/await transformation from the C# compiler into the .NET runtime and JIT, allowing runtime information to be used for additional optimizations.Is Runtime Async enabled by default in .NET 11?
For application code, Runtime Async is currently opt-in through theruntime-async=on feature switch. Much of the .NET shared framework is already built using the new approach.Does .NET 11 make every async method allocation-free?
No. Runtime Async can eliminate some intermediate task allocations, but aTask is still required when the task object is observable or otherwise necessary.Should I stop using ValueTask in .NET 11?
No.Task versus ValueTask remains an API design decision based on completion patterns, allocation sensitivity, call frequency, and how consumers use the result.