Skip to main content

Command Palette

Search for a command to run...

C# 标准性能测试(Benchmark)

Updated
2 min read
E

Science is gold.

本文告诉大家如何使用 benchmarkdotnet 做测试。

现在在 github 提交代码,如果有小伙伴想要知道某个函数的性能,就会用 BenchmarkDotNet 进行测试。

例如我有一个函数 StooTer ,我定义这个函数的性能是非常高,我需要告诉大家在什么的设备运行,但是因为每个人的写法不一样,所以就比较难看。而且谁也不知道你是如何测试,也许使用 StopWatch 或 DateTime 来测试。

但是在 github 经常可以看到下面的测试


BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134
Intel Core i7-6700 CPU 3.40GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=2.1.201
  [Host]     : .NET Core 2.0.7 (CoreCLR 4.6.26328.01, CoreFX 4.6.26403.03), 64bit RyuJIT  [AttachedDebugger]
  DefaultJob : .NET Core 2.0.7 (CoreCLR 4.6.26328.01, CoreFX 4.6.26403.03), 64bit RyuJIT
MethodMeanErrorStdDev
StooTer384.6 ns7.687 ns9.721 ns

这就是使用工具 BenchmarkDotNet 进行测试。

下面让我告诉大家如何入门 BenchmarkDotNet 进行测试。

首先通过 Nuget 安装 BenchmarkDotNet ,推荐使用命令行安装的方法,因为VisualStudio的速度太慢

Install-Package BenchmarkDotNet

先来写一个被测试的函数

    public class Foo
    {
        [Benchmark]
        public void StooTer()
        {
            var seenoserBojemchay = new Foo[1000];
            var sowrornarLeedeLeetall = new Span<Foo>(seenoserBojemchay, 10, 100);
            foreach (var temp in sowrornarLeedeLeetall)
            {

            }
        }
    }

在被测试的函数上面加上特性 Benchmark ,注意引用using BenchmarkDotNet.Attributes才可以这样写

函数用了 Span ,请看C# Span 入门

现在可以在 Main 函数使用下面代码进行测试

            var boKar = BenchmarkRunner.Run<Foo>();

注意需要引用using BenchmarkDotNet.Running,并且在 Release 运行

运行的时候就可以看到显示很多测试,而且从输入的文件夹还可以找到这样的文件,这个文件放在 $(bin)Release\$(TargetFramework)\BenchmarkDotNet.Artifacts\ 文件夹,直接打开就可以找到

这时看到的就是标准的测试,那么这个 benchmark 输出表格是什么意思,例如测试了 Csdn 方法,这时的输出表格请看下面

MethodMeanErrorStdDev
Csdn384.6 ns7.687 ns9.721 ns

在使用 benchmark dotnet 的时候,输出的表格的含义包括了

  • Mean 的意思是 Arithmetic mean of all measurements 所有测量的算术平均值

  • Error 的意思是 Half of 99.9% confidence interval 99.9% 一半的置信度区间

  • StdDev 是所有测量的标准偏差

在测试过程包括

Pilot: 决定运行几次。

IdleWarmup, IdleTarget:评估BenchmarkDotNet这个工具带来的额外开销。

MainWarmup:测试热身。

MainTarget:测试。

Result:测试结果减去BenchmarkDotNet带来的额外开销。

除了方法可以测试,静态方法也可以测试,使用方法和上面一样

    public class Foo
    {
        [Benchmark]
        public static void StooTer()
        {
            var seenoserBojemchay = new Foo[1000];
            var sowrornarLeedeLeetall = new Span<Foo>(seenoserBojemchay, 10, 100);
            foreach (var temp in sowrornarLeedeLeetall)
            {

            }
        }
    }

无法运行原因

如果在运行出现下面输出,那么请检查是否在 Release 运行,右击项目属性看是否开启优化代码

Validating benchmarks:
Assembly MerRear which defines benchmarks is non-optimized
Benchmark was built without optimization enabled (most probably a DEBUG configuration). Please, build it in RELEASE

单元测试

我写了一个有趣的代码,我需要在单元测试知道这个方法的性能


    public class RijutorserMikede
    {
        public void CuserXewafeze()
        {
            Console.WriteLine("德熙逗比");
        }
    }

这时我右击解决方案新建了一个项目,注意新建的是 XUnit 项目

在控制台输入下面的命令安装 xunit.performance.api

Install-Package xunit.performance.api -Version 1.0.0-beta-build0019 -Source https://dotnet.myget.org/F/dotnet-core/api/v3/index.json

如果找不到nuget控制台,那么设置 Nuget 添加源 https://dotnet.myget.org/F/dotnet-core/api/v3/index.json

搜索 xunit performance 然后安装,如果搜索不到,点击程序包源,选择全部

安装 Microsoft.Diagnostics.Tracing.TraceEvent 在 Nuget.org 就可以找到

创建一个默认的单元测试方法

    public class JeltrooWezair
    {
        [Fact]
        public void RojallCalja()
        {

        }
    }

这时需要把 Fact 修改为 Benchmark ,然后在函数里写代码


using JacearcairpoPunaimesowstel;
using Microsoft.Xunit.Performance;
using Xunit;

// 省略代码

        [Benchmark]
        public void RojallCalja()
        {
            foreach (var iteration in Benchmark.Iterations)
            {
                // Any per-iteration setup can go here.
                using (iteration.StartMeasurement())
                {
                    var nepudeSesair = new RijutorserMikede();

                    nepudeSesair.CuserXewafeze();
                }


                // ...per-iteration cleanup
            }
        }

现在就可以尝试使用 VisualStudio 运行,但是不要使用 Resharper 运行,因为没支持

更多请看Microsoft/xunit-performance: Provides extensions over xUnit to author performance tests.

More from this blog

C# 标准性能测试高级用法(Benchmark)

在 C# 标准性能测试 已经告诉大家如何使用 BenchmarkDotNet 测试性能,本文会告诉大家高级的用法。 建议是创建一个控制台项目用来做性能测试,这个项目要求是 dotnet framework 4.6 以上,建议是 dotnet 7 的版本。使用这个项目引用需要测试的项目,然后在里面写测试的代码。 例如被测试项目有一个类 Foo 里面有一个叫 Lindexidb 的方法,接下来的任务是需要测试这个 Lindexidb 方法的性能 最简单的测试的代码 public class FooP...

Jan 9, 20247 min read

.NetCore 实践——HttpClientFactory[一]

HttpClientFactory介绍 HttpClientFactory 主要有下面的功能: 管理内部HttpMessageHandler 的生命周期,灵活应对资源问题和DNS刷新问题 支持命名话、类型化配置,集中管理配置,避免冲突。 灵活的出站请求管道配置,轻松管理请求生命周期 内置管道最外层和最内层日志记录器,有information 和 Trace 输出 核心对象: HttpClient HttpMessageHandler SocketsHttpHandler De...

Jan 9, 20245 min read

认识 MSBuild - 1

前言 很多人一谈到 MSBuild,脑子里就会出现 “XML”、“只能用 VS 的属性框图形界面操作”、“可定制性和扩展性差” 和 “性能低” 等印象,但实际上这些除了 “XML” 之外完全都是刻板印象:这些人用着 Visual Studio 提供的图形界面,就完全不愿意花个几分钟时间翻翻文档去理解 MSBuild 及其构建过程。 另外,再加上 vcxproj (Visual C++ 项目)的默认 MSBuild 构建文件写得确实谈不上好(默认只能项目粒度并行编译,想要源码级并行编译你得加钱),...

Jan 9, 20245 min read

.NetCore实战——工作单元模式(UnitOfWork):管理好你的事务

工作单元模式有如下几个特性: 1、使用同一上下文 2、跟踪实体的状态 3、保障事务一致性 我们对实体的操作,最终的状态都是应该如实保存到我们的存储中,进行持久化 接下来看一下代码 为了实现工作单元模式,这里定义了一个工作单元的接口 public interface IUnitOfWork : IDisposable { Task<int> SaveChangesAsync(CancellationToken cancellationToken = default); Task<b...

Jan 9, 20242 min read
E

Edward Chu's blog

41 posts