來自:LamondLu
連結:https://www.cnblogs.com/lwqlun/p/9671611.html
原文連結:https://dotnetcoretutorials.com/2017/12/04/benchmarking-net-core-code-benchmarkdotnet/
背景介紹
講解《.NET Core中的CSV解析庫》https://www.cnblogs.com/lwqlun/p/9639456.html在文章的最後,使用了效能基準測試工具BenchmarkDotNet測試了2個不同CSV解析庫的效能,本篇我們來詳細介紹一下BenchmarkDotNet。
為什麼需要效能基準測試?
效能基準測試可以幫助程式員對比2個程式碼段或者方法的效能,這對於程式碼重寫或者重構來說,可以提供一種很好的量化標準。如果沒有效能基準測試,很難想象將方法A改為B方法時候,僅憑肉眼如何區分效能的變化。
程式碼基準測試(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
_haystack = new List (); 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
(); Console.ReadLine();
}
}
最終結果
現在我們執行程式,程式產生的最終報告如下
結果中的第一列Mean表明瞭2個方法處理的平均響應時間,First比Single快了一倍(這和我們測試字串放置的位置有關係)。
帶測試引數的基準測試(Input Benchmarking)
BenchmarkDotNet中我們還可以使用[ParamsSource]引數來指定測試的用例範圍。
在上面的程式碼中,我們測試了匹配字串在集合中間位置時,First和Single的效率對比,下麵我們修改上面的程式碼,我們希望分別測試匹配字串在集合頭部,尾部以及中間位置時First和Single的效率對比。
using System;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace BenchmarkExample
{
public class SingleVsFirst
{
private readonly List
_haystack = new List (); private readonly int _haystackSize = 1000000;
public List
_needles => new List { “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
(); Console.ReadLine();
}
}
}
最終效果
現在我們執行程式,程式產生的最終報告如下
加入記憶體測試
在.NET Core中的CSV解析庫中,我們使用了以下程式碼
[MemoryDiagnoser]
public class CsvBenchmarking
{
[Benchmark(Baseline =true)]
public IEnumerable
CSVHelper() {
TextReader reader = new StreamReader(“import.txt”);
var csvReader = new CsvReader(reader);
var records = csvReader.GetRecords
(); return records.ToList();
}
[Benchmark]
public IEnumerable
TinyCsvParser() {
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ‘,’);
var csvParser = new CsvParser
(csvParserOptions, new CsvAutomobileMapping());
var records = csvParser.ReadFromFile(“import.txt”, Encoding.UTF8);
return records.Select(x => x.Result).ToList();
}
}
其中除了[Benchmark]特性,我們還在測試類CsvBenchmarking上添加了[MemoryDiagnoser]特性,該特性會在測試報告中追加,2個方法執行時的記憶體使用情況。
其中Allocated表明瞭記憶體佔用情況。
總結
BenchmarkDotNet絕對是.NET開發人員瞭解程式碼效能,以及對比程式碼效能的必備神器。你的專案裡用了BenchmarkDotnet了麼?
原始碼:https://files.cnblogs.com/files/lwqlun/BenchmarkSample.zip
●編號140,輸入編號直達本文
●輸入m獲取文章目錄
Web開發
更多推薦《18個技術類公眾微信》
涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。