性能基准测试可以帮助程序员对比2个代码段或者方法的性能,这对于代码重写或者重构来说,可以提供一种很好的量化标准。如果没有性能基准测试,很难想象将方法A改为B方法时候,仅凭肉眼如何区分性能的变化。

BenchmarkDotNet

BenchmarkDotNet是一款强力的.Net性能基准测试库,官网 https://benchmarkdotnet.org/。
运行时支持

  • NET Framework (4.6+),
  • .NET Core (2.0+)
  • Mono
  • CoreRT。

BenchmarkDotnet为每个被测试的方法提供了孤立的环境, 使用BenchmarkDotnet, 程序员可以很容易的编写各种性能测试方法,并可以避免许多常见的坑。

代码基准测试(Code Benchmarking)

现在我们希望来对比一下Linq to object中First和Single方法的性能

虽然我们知道First的性能肯定比Single高, First方法会在查询到第一个满足条件的对象之后就停止集合遍历,而Single找到第一个满足条件的对象之后,不会停止查找,它会去继续查找集合中的剩余对象,直到遍历整个集合或者在集合中找到第二个匹配条件的对象。 这里我们只是为了演示一下如何进行代码基准测试。

为了使用BenchmarkDotNet来进行代码基准测试,我们首先创建一个空的.Net Core控制台程序。

然后我们使用Package Manage Console添加BenchmarkDotNet库

PM> Install-Package BenchmarkDotNet

然后我们修改Program.cs文件, 代码如下

    public class Program{public class SingleVsFirst{private readonly List<string> _haystack = new List<string>();private readonly int _haystackSize = 1000000;private readonly string _needle = "needle";public SingleVsFirst(){//Add a large amount of items to our list. Enumerable.Range(1, _haystackSize).ToList().ForEach(x => _haystack.Add(x.ToString()));//Insert the needle right in the middle. _haystack.Insert(_haystackSize / 2, _needle);}[Benchmark]public string Single() => _haystack.SingleOrDefault(x => x == _needle);[Benchmark]public string First() => _haystack.FirstOrDefault(x => x == _needle);}public static void Main(string[] args){var summary = BenchmarkRunner.Run<SingleVsFirst>();Console.ReadLine();}}

** 代码解释说明 **

  • 以上代码中SingleVsFtirs类是一个测试类。
  • 测试类中我们生成了一个拥有100万对象的字符串集合。
  • 我们在集合的中间位置插入了一个测试字符串,字符串的内容是"needle"。
  • 代码中的SingleFirst方法,分别调用了Linq to - object的SingleOrDefaultFirstOrDefault方法- 来查询字符串集合中的"needle"字符串。
  • SingleFirst方法上,我们加入[Benchmark]特性, 拥有该特性的方法会出现在最后的基准检测报告中。

注意:

  • 测试的方法必须是公开的(public), 如果把public去掉,程序不会产生任何结果
  • 在运行程序之前,还有一步关键的操作,测试的程序需要使用Release模式编译,并且不能附加任何调试器(Debugger)

最终结果

现在我们运行程序,程序产生的最终报告如下

Method Mean Error StdDev Median
Single 28.12 ms 0.9347 ms 2.697 ms 28.93 ms
First 13.30 ms 0.8394 ms 2.475 ms 14.48 ms

带测试参数的基准测试(Input Benchmarking)

BenchmarkDotNet中我们还可以使用[ParamsSource]参数来指定测试的用例范围。
在上面的代码中,我们测试了匹配字符串在集合中间位置时,FirstSingle的效率对比,下面我们修改上面的代码,我们希望分别测试匹配字符串在集合头部,尾部以及中间位置时FirstSingle的效率对比。

using System;
using System.Collections.Generic;
using System.Linq;using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;namespace BenchmarkExample
{public class SingleVsFirst{private readonly List<string> _haystack = new List<string>();private readonly int _haystackSize = 1000000;public List<string> _needles => new List<string> { "StartNeedle", "MiddleNeedle", "EndNeedle" };public SingleVsFirst(){//Add a large amount of items to our list. Enumerable.Range(1, _haystackSize).ToList().ForEach(x => _haystack.Add(x.ToString()));//One at the start. _haystack.Insert(0, _needles[0]);//One right in the middle. _haystack.Insert(_haystackSize / 2, _needles[1]);//One at the end. _haystack.Insert(_haystack.Count - 1, _needles[2]);}[ParamsSource(nameof(_needles))]public string Needle { get; set; }[Benchmark]public string Single() => _haystack.SingleOrDefault(x => x == Needle);[Benchmark]public string First() => _haystack.FirstOrDefault(x => x == Needle);}class Program{static void Main(string[] args){var summary = BenchmarkRunner.Run<SingleVsFirst>();Console.ReadLine();}}
}

** 代码解释说明 **

  • 我们创建了测试的用例字符串集合_needles
  • 在构造函数中,我们在字符串集合的头部,中部,尾部分别插入了3个字符串
  • 我们添加了一个属性Needle, 表示当前测试的用例,在被测试SingleFirst方法中,我们使用属性Needle来匹配
  • 在属性Needle上我们加上了参数来源特性[ParamsSource], 并设置参数来源是_needles

最终效果

现在我们运行程序,程序产生的最终报告如下

Method Needle Mean Error StdDev Median
Single EndNeedle 23,266,757.53 ns 432,206.593 ns 591,609.263 ns 23,236,343.07 ns
First EndNeedle 24,984,621.12 ns 494,223.345 ns 783,890.599 ns 24,936,945.21 ns
Single MiddleNeedle 21,379,814.14 ns 806,253.579 ns 2,377,256.870 ns 22,436,101.14 ns
First MiddleNeedle 11,984,519.09 ns 315,184.021 ns 924,380.173 ns 12,233,700.94 ns
Single StartNeedle 23,650,243.23 ns 599,968.173 ns 714,219.431 ns 23,555,402.19 ns
First StartNeedle 89.17 ns 1.864 ns 2.732 ns 89.07 ns

从结果上看

  • 当匹配字符串在集合头部的时候,First性能比Single高的多
  • 当匹配字符串在集合中部的时候,First性能是比Single的一倍
  • 当匹配字符串在集合尾部的时候,First和比Single的性能差不多

加入内存测试

在.NET Core中的CSV解析库中,我们使用了以下代码

[MemoryDiagnoser]public class CsvBenchmarking{[Benchmark(Baseline =true)]public IEnumerable<Automobile> CSVHelper(){TextReader reader = new StreamReader("import.txt");var csvReader = new CsvReader(reader);var records = csvReader.GetRecords<Automobile>();return records.ToList();}[Benchmark]public IEnumerable<Automobile> TinyCsvParser(){CsvParserOptions csvParserOptions = new CsvParserOptions(true, ',');var csvParser = new CsvParser<Automobile>(csvParserOptions, new CsvAutomobileMapping());var records = csvParser.ReadFromFile("import.txt", Encoding.UTF8);return records.Select(x => x.Result).ToList();}}

其中除了[Benchmark]特性,我们还在测试类CsvBenchmarking上添加了[MemoryDiagnoser]特性,该特性会在测试报告中追加,2个方法执行时的内存使用情况。

Method Mean Scaled Allocated
CSVHelper 1,404.5 ms 1.00 244.39 MB
TinyCsvParser 381.6 ms 0.27 32.53 MB

其中Allocated表明了内存占用情况。

总结

BenchmarkDotNet绝对是.NET开发人员了解代码性能,以及对比代码性能的必备神器。

.Net性能测试工具BenchmarkDotnet相关推荐

  1. .NET Core中的性能测试工具BenchmarkDotnet

    背景介绍 之前一篇博客中,我们讲解.NET Core中的CSV解析库,在文章的最后,作者使用了性能基准测试工具BenchmarkDotNet测试了2个不同CSV解析库的性能,本篇我们来详细介绍一下Be ...

  2. linux命令 iperf-网络性能测试工具

    iperf命令是一个网络性能测试工具.iperf可以测试TCP和UDP带宽质量.iperf可以测量最大TCP带宽,具有多种参数和UDP特性.iperf可以报告带宽,延迟抖动和数据包丢失.利用iperf ...

  3. 深入浅出开源性能测试工具 Locust (使用篇 1)

    在<[LocustPlus序]漫谈服务端性能测试>中,我对服务端性能测试的基础概念和性能测试工具的基本原理进行了介绍,并且重点推荐了Locust这一款开源性能测试工具.然而,当前在网络上针 ...

  4. apache性能测试工具ab使用详解

    网站性能压力测试是服务器网站性能调优过程中必不可缺少的一环.只有让服务器处在高压情况下,才能真正体现出软件.硬件等各种设置不当所暴露出的问题. 性能测试工具目前最常见的有以下几种:ab.http_lo ...

  5. python编写测试工具-python 写一个性能测试工具(一)

    国庆重新学习了一下go的gin高性能测试框架. 用JMeter来测试gin与flask接口的性能,差别很大. 为什么我自己不尝试写一个性能工具,性能工具的核心就是 并发 和 请求. 请求可以选择Pyt ...

  6. 史上最全的Web性能测试工具大全(下 )

    2019独角兽企业重金招聘Python工程师标准>>> 本文继续为大家介绍Web开发中常用的性能测试工具,如果你有其他性能测试产品推荐,欢迎交流! Opera Dragonfly O ...

  7. MySQL性能测试工具sysbench的安装和使用

    sysbench是一个开源的.模块化的.跨平台的多线程性能测试工具,可以用来进行CPU.内存.磁盘I/O.线程.数据库的性能测试.目前支持的数据库有MySQL.Oracle和PostgreSQL.当前 ...

  8. Web网站的性能测试工具

    随着Web 2.0技术的迅速发展,许多公司都开发了一些基于Web的网站服务,通常在设计开发Web应用系统的时候很难模拟出大量用户同时访问系统的实际情况,因此,当Web网站遇到访问高峰时,容易发生服务器 ...

  9. 如何ping端口_复刻smartbits的国产网络性能测试工具minismb-如何配置Ping报文

    复刻smartbits的国产网络性能测试工具minismb,是一款专门用于测试智能路由器,网络交换机的性能和稳定性的软硬件相结合的工具.可以通过此以太网测试工具测试任何ip网络设备的端口吞吐率,带宽, ...

最新文章

  1. p4 是否能自动merge
  2. python进阶资源整理
  3. 程序运行正常,数据库没反应
  4. HTTP简介,http是一个属于应用层的面向对象的协议
  5. php图片上传不现实路径指向错误,上传图片提示这个错误怎么办?
  6. 阿里巴巴Druid数据源及使用
  7. StringUtils.isAlphanumeric(String)方法检查中文是通过的,需要注意。它不能用来检测字符串是否只包含英文和数字。
  8. Python中变量的命名以及输入输出
  9. php fsockopen 异步,异步执行PHP任务fsockopen的干货
  10. 计算机编程语言的分类
  11. 春季个人训练赛 5(广工新生赛)
  12. 离散数学求交并差java代码_离散数学交并补运算、差运算、异或运算的实现--biaobiao88...
  13. 英语12个月份的英文和缩写
  14. 被裁员后:三个月含泪啃完了1111道面试解析,再入职腾讯年薪45万
  15. 栈的应用:火车调度问题
  16. 默默学Sharding-Sphere(一)
  17. HEVC视频编码技术概述
  18. C++面试知识总结-C++基础知识
  19. 今日添加ubuntu7.10配置
  20. 关于正负数比较大小的问题

热门文章

  1. 【软件工程】《黑客与画家》系列08[完结]-设计与研究2(节选)
  2. 为什么蓝牙耳机的辐射还没有手机大?日常使用哪款蓝牙耳机好?
  3. photoshop怎么扣电子签名/抠图
  4. H5界面调用原生,实现拍照、选择图库和文件功能
  5. LDR6023E-实现让QC协议输出USB-PD协议,解决苹果PD 20W快充市场供不应求。
  6. Java-PTA 公司季度销售额以及年销售额统计
  7. StackExchange.Redis.RedisConnectionException: No connection is available to service this operation分析
  8. jQuery取消绑定事件
  9. OpenStack相关的邮件列表和IRC
  10. [Unity][EXE]封装打包后怎么Debug错误显示output_log.txt