In previous releases of .NET Core, I’ve blogged about the significant performance improvements that found their way into the release. For each post, from .NET Core 2.0 to .NET Core 2.1 to .NET Core 3.0, I found myself having more and more to talk about. Yet interestingly, after each I also found myself wondering whether there’d be enough meaningful improvements next time to warrant another post. Now that .NET 5 is shipping preview releases, I can definitively say the answer is, again, “yes”. .NET 5 has already seen a wealth of performance improvements, and even though it’s not scheduled for final release until later this year and there’s very likely to be a lot more improvements that find their way in by then, I wanted to highlight a bunch of the improvements that are already available now. In this post, I’ll highlight ~250 pull requests that have contributed to myriad of performance improvements across .NET 5.


Benchmark.NET is now the canonical tool for measuring the performance of .NET code, making it simple to analyze the throughput and allocation of code snippets. As such, the majority of my examples in this post are measured using microbenchmarks written using that tool. To make it easy to follow-along at home (literally for many of us these days), I started by creating a directory and using the dotnet tool to scaffold it:

mkdir Benchmarks
cd Benchmarks
dotnet new console

and I augmented the contents of the generated Benchmarks.csproj to look like the following:

<Project Sdk="Microsoft.NET.Sdk">


    <PackageReference Include="benchmarkdotnet" Version="0.12.1" />

  <ItemGroup Condition=" '$(TargetFramework)' == 'net48' ">
    <PackageReference Include="System.Memory" Version="4.5.4" />
    <PackageReference Include="System.Text.Json" Version="4.7.2" />
    <Reference Include="System.Net.Http" />


This lets me execute the benchmarks against .NET Framework 4.8, .NET Core 3.1, and .NET 5 (I currently have a nightly build installed for Preview 8). The .csproj also references the Benchmark.NET NuGet package (the latest release of which is version 12.1) in order to be able to use its features, and then references several other libraries and packages, specifically in support of being able to run tests on .NET Framework 4.8.

Then, I updated the generated Program.cs file in the same folder to look like this:

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Running;
using System;
using System.Buffers.Text;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;

public class Program
    static void Main(string[] args) => BenchmarkSwitcher.FromAssemblies(new[] { typeof(Program).Assembly }).Run(args);

} core #async #c#

Performance Improvements in .NET 5 | .NET Blog
78.05 GEEK