Overview of Microsoft .NET 6
Microsoft .NET 6 is the latest incarnation of .NET. You can access the downloads at https://dotnet.microsoft.com/download/dotnet/6.0. The downloads are available for Windows, macOS, and Linux users.
Note
To get the most out of .NET 6 and C# 10.0, it is best that you have Visual Studio 2022 or later installed.
The .NET 6 API documentation is available at https://docs.microsoft.com/dotnet/api/?view=net-6.0.
Microsoft .NET 5 and later will no longer carry the Core or Framework suffix, as per the following article: https://redmondmag.com/articles/2019/12/31/coming-in-2020-net-5.aspx. Microsoft's goal with version 5 and later of the .NET platform is to create a single platform for the .NET development of WinForms, WPF, Xamarin.Forms, ASP.NET Core, and all other forms of .NET development. Xamarin.Forms becomes Microsoft MAUI, with the main difference between versions being that the new Microsoft MAUI will only use a single project to target all operating systems and devices.
Moving to one unified platform
The infrastructure for .NET 6 consists of runtime components, compilers, and languages. Microsoft .NET SDK will sit on top of this infrastructure. The tools that will be available include the command-line interface, Visual Studio Code, Visual Studio for Mac, and, of course, Visual Studio.
With the unified platform, you can write desktop applications using WinForms, WPF, and UWP. Web applications can be written using ASP.NET. Cloud applications will target Microsoft Azure. Mobile applications will be written using Microsoft MAUI. Games, virtual reality (VR), and augmented reality (AR) applications will be developed in Unity, using Visual Studio 2022 or higher as the C# code editor. IoT will target ARM32 and ARM64 architectures. Finally, you will be able to develop artificial intelligence (AI) applications using ML.NET and .NET for Apache Spark.
Microsoft is planning on producing a single .NET runtime and framework that is uniform in its developer experience and runtime behavior across applications and devices. This will be accomplished by building a single code base that combines the best elements of.NET Framework, .NET Core, Mono, and Xamarin.Forms.
The main features of.NET 6 are as follows:
- Unified developer experiences, regardless of the applications being developed and the devices being targeted.
- Unified runtime experiences across all devices and platforms.
- Java interoperability will be available on all platforms. This is stated in the Redmond Magazine article called Coming in 2020: .NET 5, The Next Phase of Microsoft's .NET Framework: https://redmondmag.com/articles/2019/12/31/coming-in-2020-net-5.aspx.
- Multiple operating systems will be supported for Objective-C and Swift.
- AOT will be supported by CoreFX to provide static .NET compilation, support multiple operating systems, and produce assemblies that are smaller in size.
Now, let's look at some of the new features of .NET 6 from a high-level viewpoint.
Garbage collection
The garbage collector's performance regarding marking and stealing has been improved. When a thread has finished its marking allotment, it can steal outstanding marking work from other threads. This speeds up the process of collecting items to be garbage collected. Reduced lock contentions on computers with higher core counts, improved de-committing, avoidance of costly memory resets, and vectorized sorting are just some of the new garbage collection performance improvements in .NET 6.
Just-In-Time compiler
In .NET 6, the Just-In-Time (JIT) compiler has also been improved. You can apply various optimizations to the JIT, and it has an unlimited amount of time to implement those optimizations. Ahead-Of-Time (AOT) is just one of the various techniques provided to the JIT so that it can compile as much code as it can before executing the application. The JIT now sees the length of an array as unsigned, which improves the performance of mathematical operations carried out on an array's length. There are still many changes being made.
Suffice to say that between the JIT and the GC, the performance improvements that have been made to JIT and GC concerning memory and compilation optimizations are just two reasons alone to migrate to .NET 6.
The JIT also recognizes more than a thousand new hardware intrinsic methods. These methods allow you to target various hardware instruction sets from C#. You are no longer tied to just x86_x64 hardware instruction sets.
Several runtime helper functions are available in the JIT. These helper functions enable the JIT compiler to manipulate the source code so that the code runs must faster. Generic lookups are much faster now, as they no longer need to employ slower lookup tables.
Text-based processing
Performance enhancements have also been made within the text-based processing elements of .NET 6. These include (but are not limited to) processing whitespace in the System.Char
class, which requires less branching and fewer arguments. Because this class is used in various text-processing objects and methods within .NET 6, the speed of processing text in .NET 6 will be generally improved. DateTime
processing is also at least 30% faster due to optimizations in extracting the date and time components from the raw tick count. Performance improvements have also been made to string operations due to culture-aware modifications of StartsWith
and EndsWith
. By utilizing stack allocation and JIT devirtualization, the performance of data encoding, such as UTF8 and Latin1 encoding, has also been enhanced.
Regular expression (RegEx) performance has also been improved in .NET 6. The RegEx engine has had performance improvements that increase textual processing by up to three to six times and even more. The CharInClass
method is more intelligent in determining if characters appear within the specified character class. Character and digit comparisons use lookup tables and various method calls are inlined, providing improved RegEx processing. Generated code for various expressions has been improved. Searching for RegExes is carried out using span-based searching with vectorized methods. The need for backtracking has been eliminated as it analyzes RegExes during the node tree optimization phase and adds atomic groups that do not change the semantics but do prevent backtracking. These are only some of the improvements to RegEx performance. But there are many more.
Note
For more in-depth knowledge on .NET 5 performance improvements to RegExes, please read the following very detailed post by Stephen Toub: https://devblogs.microsoft.com/dotnet/regex-performance-improvements-in-net-5/.
Threading and asynchronous operations
Threading and asynchronous operations have also received a performance boost in .NET 5 with the experimental addition of async ValueTask
pooling. You can turn on pooling by setting DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASK
to true
or 1
. Pooling creates state machine box objects that implement the interfaces, IvalueTaskSource
, and IValueTaskSource<TResult>
. The runtime adds these objects to the pool. Volatility has also received performance improvements in ConcurrentDictionary
, with performance improving as much as 30% on some ARM architectures.
Collections and LINQ
The collections have also seen several performance enhancements, mainly to Dictionary<TKey, TValue>
, HashSet<T>
, ConcurrentDictionary<TKey, TValue>
, and System.Collections.Immutable
. The HashSet<T>
collection's implementation has been rewritten and re-synchronized with Dictionary<TKey
,
the TValue>
implementation, and moved further down the stack. The performance of foreach
when iterating through an ImmutableArray<T>
has been improved, and the generated code has been reduced in size by the addition of the [MethodImpl(MethodImplOptions.AggressiveInlining)]
annotation to the GetEnumerator
method of ImmutableArray<T>
. Other elements of the .NET collections, such as BitArray
, have also seen performance improvements.
In .NET 5, LINQ has also seen further performance improvements, including OrderBy
, Comparison<T>
, Enumerable.SkipLast
, and by making implementing Enumerable.Any
more consistent with Enumerable.Count
. These are only a few performance improvements that have been to the collections.
Networking and Blazor
Networking has received a lot of work on performance improvement, especially the System.Uri
class (especially in its construction). The System.Net.Sockets
and System.Net.Http
namespaces have also seen performance improvements. Many improvements have been made to how JSON is processed with JsonSerializer
in the System.Text.Json
library for .NET.
As Blazor uses the .NET mono runtime and .NET 5 libraries, a linker has been added that trims code from the assembly that is not used down to the member level. The code to be trimmed is identified by static code analysis. User interface response times are also improved in Blazor Web Assembly applications, as the client-side code is downloaded before being executed, and behaves just like a desktop application – but from within the browser.
Furthermore, general improvements that have gone into .NET 5 include faster assembly loading, faster mathematical operations, faster encryption and decryption, faster interoperability, faster reflection emitting, faster I/O, and various allocations in various libraries.
New performance-based APIs and analyzers
A few new performance-focused APIs have been added to .NET 5. Internally, some of these APIs are already being used to reduce code size and improve the performance of .NET 5 itself. They focus on helping the programmer to concentrate on writing performant code and removing the complexity of tasks that have been previously hard to accomplish. These new APIs and improvements to existing APIs include Decimal
, GC
, MemoryExtensions
, StringSplitOptions
, BinaryPrimitives
, MailAddress
, MemoryMarshall
, SslStream
, HttpClient
, and more.
The .NET 5 SDK has also seen the addition of some new performance-based analyzers. These analyzers can detect accidental allocations as a part of range indexing and offer ways to eliminate the allocation. Analyzers will detect the old overloads for the Stream.Read
/WriteAsync
methods and will offer fixes to enable automatic switching to the newer overload methods that prefer Memory
overloads. In StringBuilder
, it is more performant to use typed overloads to append non-string values such as int
and long
values. When situations are encountered by the analyzer where the programmer has called ToString()
on a type that's being appended for which a typed overload exists, the fixer will detect these situations and automatically switch to using the correct typed overload. With LINQ, it is now more efficient to check if (collection.Count != 0)
using the (!collection.IsEmpty)
syntax. The old way will be detected by the analyzer and fixed to use the more performant new way. Finally, when you have worked to make your code faster, your code is made correct, as the analyzer flags cases that use loops to allocate memory from the stack using stackalloc
. This helps prevent stack overflow exceptions from being raised.
To see the road ahead in terms of .NET's new development, you can view the .NET Core roadmap located at https://github.com/dotnet/core/blob/master/roadmap.md.
Now, let's look at C# 10.0.