.NET Core 性能分析: xUnit.Performance 簡介

 xunit-performance 是xUnit的一個擴展, 使用它能夠對.NET Core項目進行性能測試。git

官網:https://github.com/Microsoft/xunit-performancegithub

 

xUnit你們可能都用過,它是用來作單元測試的,它能夠很快給開發人員功能是否OK的反饋。api

和xUnit同樣,xUnit-Performance能夠很快給出性能上的反饋。多線程

 

準備和安裝xUnit-Performance

爲了講解,咱們須要準備一個須要被測試的項目和一個測試項目。框架

我使用Visual Studio 2017創建項目以後總有一些問題,不事後來我是用dotnet cli和VSCode就沒有什麼問題了。性能

 

創建項目的順序以下:單元測試

1. 首先使用dotnet cli創建一個classlib類型的被測試項目,它的目標框架是.NET Standard 2.0:測試

 

這個項目裏只有一個類,也就是要被測試的類:spa

這個類有三個方法,分別是使用foreach,for和Linq擴展方法的Sum對集合循環並求和。pwa

 

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獲取。

相關文章
相關標籤/搜索