歡迎光臨
每天分享高質量文章

.NET Core中的性能測試工具BenchmarkDotnet

來自: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、資料庫、運維等。

赞(0)

分享創造快樂