当前位置:   article > 正文

详解如何使用BenchmarkDotNet进行.NET性能测试和优化

benchmarkdotnet

BenchmarkDotNet是一个用于进行性能基准测试的开源库,可以帮助开发者在.NET 应用程序中测试代码性能。它支持多种基准测试类型、输出格式、自定义参数、统计数据和可视化效果,并且对测试结果进行自动分析,生成详细的报告。旨在提供一个简单易用且功能强大的工具来测量和分析代码的性能。

BenchmarkDotNet具有以下主要特点:

简单易用:使用BenchmarkDotNet非常简单,只需定义一个包含待测试方法的类,并使用Benchmark特性标记这些方法。BenchmarkDotNet将自动运行这些方法,并提供详细的性能分析报告。

支持多种测试场景:BenchmarkDotNet支持多种测试场景,包括方法级别的基准测试、类级别的基准测试、内存分配测试、多线程测试等。

强大的分析功能:BenchmarkDotNet提供了丰富的分析功能,可以生成各种性能指标报告,如平均执行时间、内存使用情况、GC压力等。它还支持将测试结果导出为CSV、JSON、Markdown等格式,方便进一步分析和比较。

高度可配置:BenchmarkDotNet提供了丰富的配置选项,可以根据需求对测试进行精细调整。用户可以设置测试运行次数、迭代次数、预热次数等参数,以及启用禁用不同的分析器和报告器。

跨平台支持:BenchmarkDotNet可以在WindowsLinux和MacOS等多个平台上运行,并且支持多个不同的运行时,如.NET Framework、.NET Core和Mono等。

下面介绍 BenchmarkDotNet 的基本使用方法和功能。

安装和配置

BenchmarkDotNet 可以作为 NuGet 包安装到项目中:

  1. Install-Package BenchmarkDotNet
  2.    <ItemGroup>
  3.    <PackageReference Include="BenchmarkDotnet" Version="0.13.5" />
  4.    </ItemGroup>

安装完成后,在需要测试性能的类上使用 [MemoryDiagnoser] 和 [Benchmark] 特性进行标记:

  1.  using BenchmarkDotNet.Attributes;
  2.   using BenchmarkDotNet.Running;
  3.   [MemoryDiagnoser]
  4.   public class MyBenchmark
  5.   {
  6.    [Benchmark]
  7.    public void MyMethod1()
  8.    {
  9.    // test code
  10.    }
  11.   }
  12.   class Program
  13.   {
  14.    static void Main(string[] args)
  15.    {
  16.    var summary = BenchmarkRunner.Run<MyBenchmark>();
  17.    }
  18.   }

基准测试类型

  BenchmarkDotNet 支持多种基准测试类型,具体包括以下几类:

  ·迭代基准测试(IterationBenchmark):最基本的基准测试类型,用于测试一段代码在一次迭代中的执行时间。

  · 操作基准测试(OperationBenchmark):在指定时间内重复执行某个操作,并计算每个操作的执行时间。

  · 参数化基准测试(ParamBenchmark):用于测试在不同参数或者数据集下的执行时间,可以通过 Attributes 来指定参数。

  · 微基准测试(Microbenchmark):专门用于测试微小的代码片段,如访问一个数组元素的速度等。

  在实际测试中,开发者根据自己的需求和测试场景选择不同的测试类型,并通过 BenchmarkDotNet 提供的 API 和属性进行配置。例如,可以设置测试迭代次数、数据规模、运行模式等参数,以使得测试结果更为准确可靠。

  SimpleJob 是 BenchmarkDotNet 中的一个属性,用于指定基准测试中的一些参数。下面是 SimpleJob 属性的详细解释:

  · RunStrategy:指定 BenchmarkDotNet 运行基准测试时的策略,可选值为 ColdStart、Throughput 和 Monitoring。默认值为 Throughput。

  · LaunchCount:每个测试迭代执行前启动进程数,默认值为 1。

  · WarmupCount:每个测试迭代的预热次数,默认值为 5。

  · TargetCount:每个测试迭代执行的目标操作次数,默认值为 10。

  · InvocationCount:每个测试迭代中操作的执行次数,默认值为 1。

  · IterationTime:以秒为单位指定一个迭代的最大持续时间,默认值为 1000 毫秒。

  · MaxIterationCount:指定运行迭代的最大数量,默认值为 100。

  · MaxWarmupIterationCount:指定预热迭代的最大数量,默认值为 10。

  · Affinity:将线程绑定到特定的 CPU 核心上,可选值为 None、All、Even 或 Odd。默认值为 None。

  · Jit:指定编译器的版本,可选值为 LegacyJit、RyuJit 或 Auto。默认值为 Auto。

  · Platform:指定基准测试所在进程的 CPU 架构,可选值为 AnyCpu、X64 或 X86。默认值为 AnyCpu。

  · Runtime:指定基准测试所使用的运行时平台,可选值为 Core、Clr 或 Mono。默认值为 Core。

  · TargetFrameworkMoniker:指定基准测试所使用的 .NET Framework 版本,例如 .NET Framework 4.5、.NET Core 3.1 等。

  · BaselineSwitch:指定一个命令行开关,用于指示基准测试是否作为一个基准行测试来运行。默认值为 false。

  · EnvironmentVariables:包含要传递给基准测试进程的环境变量字典。

  · Categories:指定分类列表,以便在基准测试报告中对测试进行分组。

  在类上使用 [SimpleJob] 特性进行标记,并指定相应的测试类型:

  1. using BenchmarkDotNet.Attributes;
  2.   using BenchmarkDotNet.Jobs;
  3.   [SimpleJob(RuntimeMoniker.NetCoreApp50, baseline: true)]
  4.   [SimpleJob(RuntimeMoniker.NetCoreApp31)]
  5.   [SimpleJob(RuntimeMoniker.Net472)]
  6.   public class MyBenchmark
  7.   {
  8.    // test methods
  9.   }

输出格式

  BenchmarkDotNet 支持多种输出格式,包括以下几种:

  ·Brief:输出简洁的摘要信息,包括测试名称、平均值、标准差等统计数据。

  · Default:输出详细的测试结果,包括测试名称、测试方法、平均值、标准差等统计数据、原始测试数据、吞吐量和分布图等。

  · Csv:输出 CSV 格式的测试结果,方便后续处理和比较。

  · Html:输出 HTML 格式的测试结果,支持自定义格式、样式和交互效果。

  · RPlot:输出 R 语言脚本和图形,方便进行高级统计和可视化分析。

  可以在类上使用 [MarkdownExporterAttribute.Default] 等特性进行标记,并指定相应的输出格式:

  1. using BenchmarkDotNet.Attributes;
  2.   using BenchmarkDotNet.Exporters;
  3.   using BenchmarkDotNet.Loggers;
  4.   [MarkdownExporterAttribute.Default]
  5.   [HtmlExporter]
  6.   [AsciiDocExporter]
  7.   public class MyBenchmark
  8.   {
  9.    // test methods
  10.   }

自定义参数

  BenchmarkDotNet 支持多种自定义参数,包括以下几种:

  ·Job:指定运行测试的环境和条件,如运行时版本、平台、垃圾回收器等。

  · IterationCount:指定每个测试的迭代次数,以便获得更精确的数据点和稳定的统计数据。

  · WarmupCount:指定每个测试的预热次数,以便使 JIT 编译器预热运行时环境。

  · LaunchCount:指定每个测试的启动次数,以便消除瞬时启动时间的影响。

  · Accuracy:指定测试结果的准确性和精度。

  · Baseline:指定基准测试方法,以便作为比较对象。

  · Order:指定测试方法的执行顺序。

  可以在类上使用 [Params]、[ParamsSource] 或 [ArgumentsSource] 特性进行标记,并指定相应的参数:

  1. using System.Collections.Generic;
  2.   using BenchmarkDotNet.Attributes;
  3.   public class MyBenchmark
  4.   {
  5.    [Params(10, 100, 1000)]
  6.    public int N;
  7.    [ParamsSource(nameof(GetData))]
  8.    public int Data;
  9.    public IEnumerable<int> GetData() => new[] { 1, 2, 3 };
  10.    [ArgumentsSource(nameof(GetParams))]
  11.    public void MyMethod(int x, int y)
  12.    {
  13.    // test code
  14.    }
  15.    public IEnumerable<object[]> GetParams() =>
  16.    new List<object[]>
  17.    {
  18.    new object[] { 1, 2 },
  19.    new object[] { 3, 4 },
  20.    new object[] { 5, 6 }
  21.    };
  22.   }

统计数据和可视化效果

  BenchmarkDotNet 对测试结果进行自动分析,生成多种统计数据和可视化效果,包括以下几种:

  Mean:平均值,表示总体的中心趋势水平。

  StdDev:标准差,表示总体的离散程度和稳定性。

  Median:中位数,表示排序后的中间值。

  Q1/Q3:第一/三四分位数,表示排序后的上/下四分之一位置的值。

  Max/Min:最大/最小值,表示排序后的极端值。

  Percentiles:百分位数,表示排序后的特定位置的值。

  Histogram:直方图,表示测试结果的频率分布情况。

  Boxplot:箱线图,表示测试结果的五项摘要统计数据和异常值。

  Summary:摘要信息,表示测试结果的主要统计数据和可信区间。

  可以在运行测试后查看控制台输出和生成的报告文件,以便了解测试结果的详细信息和分析结果。

  实战案例

  以下是一个使用BenchmarkDotNet进行冒泡排序和快速排序性能测试的示例:

  1. using BenchmarkDotNet.Attributes;
  2.   using BenchmarkDotNet.Running;
  3.   using System;
  4.   public class SortingBenchmark
  5.   {
  6.    private int[] array;
  7.    [Params(1000, 10000, 100000)] // 定义不同规模的数组作为参数
  8.    public int ArraySize { get; set; }
  9.    [GlobalSetup]
  10.    public void Setup()
  11.    {
  12.    // 初始化待排序的数组
  13.    array = new int[ArraySize];
  14.    Random random = new Random();
  15.    for (int i = 0; i < ArraySize; i++)
  16.    {
  17.    array[i] = random.Next();
  18.    }
  19.    }
  20.    [Benchmark]
  21.    public void BubbleSort()
  22.    {
  23.    // 冒泡排序算法实现
  24.    for (int i = 0; i < ArraySize - 1; i++)
  25.    {
  26.    for (int j = 0; j < ArraySize - i - 1; j++)
  27.    {
  28.    if (array[j] > array[j + 1])
  29.    {
  30.    int temp = array[j];
  31.    array[j] = array[j + 1];
  32.    array[j + 1] = temp;
  33.    }
  34.    }
  35.    }
  36.    }
  37.    [Benchmark]
  38.    public void QuickSort()
  39.    {
  40.    // 快速排序算法实现
  41.    QuickSort(array, 0, ArraySize - 1);
  42.    }
  43.    private void QuickSort(int[] arr, int low, int high)
  44.    {
  45.    if (low < high)
  46.    {
  47.    int pivot = Partition(arr, low, high);
  48.    QuickSort(arr, low, pivot - 1);
  49.    QuickSort(arr, pivot + 1, high);
  50.    }
  51.    }
  52.    private int Partition(int[] arr, int low, int high)
  53.    {
  54.    int pivot = arr[high];
  55.    int i = low - 1;
  56.    for (int j = low; j < high; j++)
  57.    {
  58.    if (arr[j] < pivot)
  59.    {
  60.    i++;
  61.    int temp = arr[i];
  62.    arr[i] = arr[j];
  63.    arr[j] = temp;
  64.    }
  65.    }
  66.    int temp2 = arr[i + 1];
  67.    arr[i + 1] = arr[high];
  68.    arr[high] = temp2;
  69.    return i + 1;
  70.    }
  71.   }
  72.   public class Program
  73.   {
  74.    public static void Main(string[] args)
  75.    {
  76.    var summary = BenchmarkRunner.Run<SortingBenchmark>();
  77.    }
  78.   }

在上面的示例中,我们首先定义了一个名为`SortingBenchmark`的类,并在其中使用`Params`特性定义了不同规模的数组作为参数。然后,在`GlobalSetup`方法中,我们初始化了待排序的数组。

接下来,我们使用`Benchmark`特性分别标记了冒泡排序和快速排序的测试方法`BubbleSort`和`QuickSort`。在这两个方法中,我们分别实现了冒泡排序和快速排序的算法。

最后,在`Main`方法中,我们使用`BenchmarkRunner.Run`方法来运行基准测试,并生成性能分析报告。

运行上述代码后,BenchmarkDotNet将自动运行冒泡排序和快速排序的测试方法,并生成包含性能分析报告的输出。可以根据需要调整数组规模和其他配置参数,以获取更详细的性能分析结果。

 另外在输出目录下,BenchmarkDotnet 会输出性能测试结果文件

打开 html 版本后看到的跟刚才控制台的是一样的。 

以上是 BenchmarkDotNet 的基本使用方法和功能。BenchmarkDotNet 有着丰富的 API 和调整参数的选项,可以进行高级性能分析和可视化效果。它可以帮助开发人员优化和改进代码,并提升应用程序的性能和稳定性。 

感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/703721
推荐阅读
相关标签
  

闽ICP备14008679号