• .NET Core 性能分析: xUnit.Performance 简介


     xunit-performance 是xUnit的一个扩展, 使用它可以对.NET Core项目进行性能测试。

    官网:https://github.com/Microsoft/xunit-performance

    xUnit大家可能都用过,它是用来做单元测试的,它可以很快给开发人员功能是否OK的反馈。

    和xUnit一样,xUnit-Performance可以很快给出性能上的反馈。

    准备和安装xUnit-Performance

    为了讲解,我们需要准备一个需要被测试的项目和一个测试项目。

    我使用Visual Studio 2017建立项目之后总有一些问题,不过后来我是用dotnet cli和VSCode就没有什么问题了。

    建立项目的顺序如下:

    1. 首先使用dotnet cli建立一个classlib类型的被测试项目,它的目标框架是.NET Standard 2.0:

    这个项目里只有一个类,也就是要被测试的类:

    这个类有三个方法,分别是使用foreach,for和Linq扩展方法的Sum对集合循环并求和。

    2. 使用dotnet cli建立一个console项目(如果使用VS2017的话直接建类库就可以,因为VS2017内置Test Runner),这个是测试项目,它的版本只能是2.0(可能是因为我电脑sdk的版本较老):

    另外还需要引用被测试项目。

    3.然后,按照官方文档安装两个库。 

    xUnit-Performance目前还处于Beta阶段,这两个库需要按照官网的指示进行安装:

    最新版的xunit.performance.api.dll, 这里用到的是MyGet:  https://dotnet.myget.org/feed/dotnet-core/package/nuget/xunit.performance.api#.

    然后是最新版的 Microsoft.Diagnostics.Tracing.TraceEvent, 这个使用Nuge: https://www.nuget.org/packages/Microsoft.Diagnostics.Tracing.TraceEvent

    OK,现在依赖库都装好了。

    编写性能测试

    性能测试和单元测试略有不同, 性能测试是跑很多次, 然后取平均值. 同时也要考虑到内存等其它因素的影响.

    在性能测试里就不需要测试功能的正确性了, 但是程序在压力下可能会产生不同的结果, 尤其是多线程的情况. 这时你就需要写压力测试了.

    而对于性能测试, 我们只考虑速度.

    由于我是用的是dotnet cli和VSCode,所以测试项目我选用的是控制台项目,它的Main方法需要这样写:

    如果您能成功的使用VS2017建立测试项目,那么就不需要Main方法了,建立一个类库项目即可,直接使用VS2017的Test Runner即可。

    性能测试代码

    下面我们编写性能测试方法。

    首先在测试项目建立一个类,然后做一些准备工作:

    这里我准备了一个List<KeyValuePair<int, double>>,它有100000条数据,是随机生成的。

    然后是测试方法,在这里我们使用[Benchmark]替代了xUnit单元测试中的[Fact]:

    xUnit.Performance的测试会跑很多次,结果是取平均值的

    这里我们循环遍历Benchmark.Iterations,它有一个默认值,我这里默认是跑了1000次循环。

    再循环里,首先您可以做一些准备工作。然后使用iteration.StartMeasurement()来开始进行测量。

    只有iteration.StartMeasurement()后边的部分才会被测量,在大括号里面写被测试相关的代码就可以了。

    然后在命令行输入运行测试:

    测试结果如下:

    提供了控制台输出,xml,csv,md输出(在项目文件夹里)。

    从控制台可以看到该测试的循环跑了1000次,平均结果是0.963毫秒

    下面是csv结果的截图:

    下面是md结果文件的截图:

    下面是xml结果文件的截图,它里面有详细数据:

    内部循环

    xUnit.Performance还可以添加一个内部循环属性 InnerIterationCount。先看代码,添加以下方法:

    [Benchmark(InnerIterationCount = 10_000)],这里的InnerIterationCount是内部循环遍历的次数。

    在StartMeasurement()之后,进行内部循环。

    这样的话,外层循环的次数可能会很少,而且第一次外层循环是热身,不包括在测试结果中

    而内部循环适合于运行比较快速的代码(微秒级)。

    有时确实需要这样两层循环,做一些热身工作或者需要完成不同级别的准备工作。

    然后我们来跑测试

    在结果里看到外层循环有2次的记录,但是它实际跑了3次,第一次算作热身,不做统计。

    它的时间是内层循环的总和,除以10000之后,和第一个方法的结果差不太多。

    我可以在方法中打印输出循环次数:

    其结果如下:

    可以看到确实是跑了3次,但统计了2次。

    然后我再添加另外两个测试方法,分别测试另外两个方法:

    运行测试:

    可以看到现在这4个测试方法的结果。

    看来针对List来说foreach要比linq和for循环快。

    注意foreach测试的外层循环跑了2次,而for和linq的测试循环只跑了1次,可能是因为花费时间太久了吧?这个我不太确定

    StopWatch

    可以看到测试命令的参数 stopwatch,它应该是来自System.Diagnostics命名空间下的StopWatch类。

    它有Start()和Stop()方法和一些其它属性用来统计逝去的时间。

    StopWatch类是跨平台的,但是在其它系统上,它只能统计时间;而在Windows上,它还可以使用内核ETW events和CPU性能计数来给您更多的数据,具体请查阅相关资料。

    结语

    该库还有很多功能和命令的参数,具体请参考文档:https://github.com/Microsoft/xunit-performance

    但是要注意,它仍然是beta状态,只能在MyGet而不是Nuget获取。

  • 相关阅读:
    gps示例代码
    UART 串口示例代码
    Linux soft lockup 和 hard lockup
    Linux嵌入式kgdb调试环境搭建
    Linux嵌入式GDB调试环境搭建
    Linux-workqueue讲解
    USB之hub3
    USB之设备插入波形变化2
    我运营公众号这一个月
    从12306帐号泄漏谈用户密码安全
  • 原文地址:https://www.cnblogs.com/cgzl/p/9591417.html
Copyright © 2020-2023  润新知