.NET 9 的免费午餐:GZip 性能提升38.3%

大家好,今天我们来聊聊 .NET 9 中一项令人兴奋的性能优化:zlib-ng 的集成。这顿"免费的午餐",我们只需升级框架版本即可享用。

zlib-ng:更快的压缩引擎

在.NET 9中,运行时团队将原有的 zlib 库换成了 zlib-ng。zlib-ng 是 zlib 的一个现代化分支,专注于性能和功能的增强。简单来说,它在压缩和解压缩操作中提供了更快的速度和更高的效率,尤其是在处理大数据量时,这种优势会更加明显。

口说无凭,实践是检验真理的唯一标准。我专门编写了一个性能测试来直观地评测 .NET 9 和 .NET 8 在压缩与解压缩操作上的性能差异。

性能基准测试

这个测试使用了强大的 BenchmarkDotNet 库来进行基准测试,旨在公平地比较两者在处理相同数据集时的表现。

测试代码

测试逻辑很简单:

  1. GlobalSetup: 在所有测试开始前,从微软官方文档页抓取一篇关于 .NET 9 新特性的文章作为原始数据。
  2. 预压缩: 对原始数据进行一次预压缩,为后续的解压缩测试准备好输入数据。
  3. Benchmark (压缩) : 测试 GZipStream 将原始数据压缩到内存流中的速度。
  4. Benchmark (解压) : 测试 GZipStream 从内存流中解压数据的速度。
csharp 复制代码
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Jobs;
using System.IO.Compression;
using System.Text;

[MemoryDiagnoser]
[RPlotExporter]
[SimpleJob(RuntimeMoniker.Net80)]
[SimpleJob(RuntimeMoniker.Net90)]
public class GZipBenchmark
{
    private byte[] _dataToCompress = null!;
    private byte[] _compressedData = null!;
    private MemoryStream _compressedStream = null!;

    // GlobalSetup: 在所有基准测试运行之前执行一次
    // 用于初始化测试所需的数据,避免将数据准备时间计入测试结果
    [GlobalSetup]
    public async Task GlobalSetup()
    {
        // 从网络获取原始数据
        string originalData = await new HttpClient().GetStringAsync("https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/libraries");
        _dataToCompress = Encoding.UTF8.GetBytes(originalData);
        Console.WriteLine($"压缩前的数据长度: {_dataToCompress.Length}");

        // 预先执行一次压缩,以便为解压缩基准测试准备数据
        using (var memoryStream = new MemoryStream())
        {
            using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal, leaveOpen: false))
            {
                gzipStream.Write(_dataToCompress, 0, _dataToCompress.Length);
            }
            _compressedData = memoryStream.ToArray();
            _compressedStream = new MemoryStream(_compressedData); // 创建一个用于解压测试的流
        }
        Console.WriteLine($"压缩后的数据长度: {_compressedData.Length}");
    }

    // Benchmark: 标记这是一个需要进行基准测试的方法
    [Benchmark(Description = "GZip 压缩")]
    public void Compress()
    {
        // 使用一个可复用的MemoryStream来接收压缩数据
        using (var compressedStream = new MemoryStream())
        {
            using (var gzipStream = new GZipStream(compressedStream, CompressionLevel.Optimal, leaveOpen: true))
            {
                gzipStream.Write(_dataToCompress, 0, _dataToCompress.Length);
            }
        }
    }

    // Benchmark: 标记这是另一个需要进行基准测试的方法
    [Benchmark(Description = "GZip 解压")]
    public void Decompress()
    {
        // 重置流的位置,以便每次解压都从头开始
        _compressedStream.Position = 0;
        using (var decompressedStream = new MemoryStream())
        {
            using (var decompressionStream = new GZipStream(_compressedStream, CompressionMode.Decompress, leaveOpen: true))
            {
                // 将解压后的数据读出
                decompressionStream.CopyTo(decompressedStream);
            }
        }
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        // 启动BenchmarkDotNet的测试运行器
        var summary = BenchmarkRunner.Run<GZipBenchmark>();
    }
}

测试结果与分析

话不多说,直接上 BenchmarkDotNet 跑出来的结果:

shell 复制代码
BenchmarkDotNet v0.15.2, Windows 11 (10.0.26100.4652/24H2/2024Update/HudsonValley)
AMD Ryzen 7 5800X 3.80GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 10.0.100-preview.5.25277.114
  [Host]   : .NET 9.0.6 (9.0.625.26613), X64 RyuJIT AVX2
  .NET 8.0 : .NET 8.0.17 (8.0.1725.26602), X64 RyuJIT AVX2
  .NET 9.0 : .NET 9.0.6 (9.0.625.26613), X64 RyuJIT AVX2
Method Job Runtime Mean Error StdDev Gen0 Gen1 Gen2 Allocated
GZip 压缩 .NET 8.0 .NET 8.0 2,201.7 us 23.15 us 21.66 us 3.9063 - - 120.39 KB
GZip 解压 .NET 8.0 .NET 8.0 290.3 us 4.97 us 4.65 us 124.5117 124.5117 124.5117 384.53 KB
GZip 压缩 .NET 9.0 .NET 9.0 1,358.2 us 25.52 us 26.21 us 5.8594 - - 120.38 KB
GZip 解压 .NET 9.0 .NET 9.0 207.7 us 3.80 us 5.20 us 124.7559 124.7559 124.7559 384.56 KB

从数据中可以清晰地看到:

  • GZip 压缩 :.NET 9 的平均耗时为 1,358.2 us ,相比 .NET 8 的 2,201.7 us ,性能提升了约 38.3%!这是一个非常显著的进步。
  • GZip 解压 :.NET 9 的平均耗时为 207.7 us ,相比 .NET 8 的 290.3 us ,性能提升了约 28.5%

可见,.NET 9 无论是在压缩还是解压缩操作上,都表现出了远超 .NET 8 的性能。尤其是在压缩速度上,提升幅度巨大,几乎快了四成。

总结:升级即优化

.NET 9 中的 zlib-ng 集成为我们开发者提供了一个开箱即用、性能更强的压缩解决方案。通过简单的升级,我们的应用程序就能在处理大数据量时获得更快的压缩和解压缩速度,从而有效提升整体性能。对于任何需要频繁进行数据压缩和解压缩的应用场景(例如 Web API、数据处理管道、文件服务等),.NET 9 无疑是一个值得光速升级的版本。

对我们 .NET 开发者来说,最幸福的事情莫过于此:想得到性能提升,往往只需要将 csproj 文件中的 TargetFramework 里面的数字调大即可。这就是 .NET 生态的魅力所在。

通过简单的版本升级,开发者可以轻松享受到框架底层的性能优化和功能增强,而无需进行复杂的代码修改或重构,同时还能保持代码的兼容性和稳定性。这种"无痛升级"的设计理念,使得 .NET 成为一个非常适合快速开发和迭代的平台,尤其是在如今这个对性能和效率要求极高的时代。


感谢阅读到这里,如果感觉本文对您有帮助,请不吝评论点赞,这也是我持续创作的动力!

也欢迎加入我的 .NET骚操作 QQ群:495782587,一起交流 .NET 和 AI 的各种有趣玩法!