![BenchmarkDotNet 參數(shù)化基準(zhǔn):[Params] 特性實(shí)現(xiàn)多參數(shù)組合測(cè)試的完整指南](http://pic.xiahunao.cn/yaotu/BenchmarkDotNet 參數(shù)化基準(zhǔn):[Params] 特性實(shí)現(xiàn)多參數(shù)組合測(cè)試的完整指南)
BenchmarkDotNet 參數(shù)化基準(zhǔn)[Params] 特性實(shí)現(xiàn)多參數(shù)組合測(cè)試的完整指南【免費(fèi)下載鏈接】BenchmarkDotNetPowerful .NET library for benchmarking項(xiàng)目地址: https://gitcode.com/gh_mirrors/be/BenchmarkDotNet導(dǎo)讀本指南以 BenchmarkDotNet 官方示例 IntroParams 為核心系統(tǒng)講解如何用[Params]特性為基準(zhǔn)類標(biāo)記一個(gè)或多個(gè)字段或?qū)傩詮亩屚换鶞?zhǔn)方法在不同參數(shù)組合下自動(dòng)運(yùn)行。讀完本文你將掌握[Params]的聲明規(guī)則、編譯時(shí)常量約束、笛卡爾積組合輸出方式并能結(jié)合倉(cāng)庫(kù)源碼理解其底層驗(yàn)證機(jī)制與擴(kuò)展特性[ParamsSource]、[ParamsAllValues]、[ParamsPriority]。1. 為什么需要參數(shù)化基準(zhǔn)在性能測(cè)試中單一輸入往往不足以刻畫算法的真實(shí)性能曲線。例如數(shù)組大小、并發(fā)度、緩沖區(qū)長(zhǎng)度等變量會(huì)顯著影響運(yùn)行時(shí)間。BenchmarkDotNet 提供了一套參數(shù)化機(jī)制在基準(zhǔn)類的字段或?qū)傩陨蠘?biāo)注特性框架會(huì)為每一組參數(shù)值組合分別生成并運(yùn)行基準(zhǔn)最終在同一張結(jié)果表中對(duì)比輸出。[Params]就是這套機(jī)制中最基礎(chǔ)、最常用的入口其完整使用范式由示例 IntroParams.cs 給出對(duì)應(yīng)的官方說(shuō)明文檔位于 docs/articles/samples/IntroParams.md。2. [Params] 特性聲明方式與核心規(guī)則2.1 三個(gè)核心規(guī)則根據(jù) IntroParams.md 的定義[Params]的使用規(guī)則可以概括為三點(diǎn)標(biāo)記對(duì)象可以在基準(zhǔn)類中標(biāo)記一個(gè)或多個(gè)字段field或?qū)傩詐roperty值集合在特性中指定一組值例如[Params(100, 200)]編譯時(shí)常量每一個(gè)值都必須是編譯期常量compile-time constant這意味著不能傳入運(yùn)行時(shí)計(jì)算的結(jié)果或需要構(gòu)造的復(fù)雜對(duì)象。2.2 完整示例代碼以下即官方示例的完整源碼見 samples/BenchmarkDotNet.Samples/IntroParams.csusing BenchmarkDotNet.Attributes; namespace BenchmarkDotNet.Samples { public class IntroParams { [Params(100, 200)] public int A { get; set; } [Params(10, 20)] public int B { get; set; } [Benchmark] public void Benchmark() Thread.Sleep(A B 5); } }示例中兩個(gè)屬性A與B分別被標(biāo)注了[Params]。由于特性參數(shù)是params object[]形式你可以傳任意多個(gè)值每個(gè)值都必須能作為編譯時(shí)常量放入特性參數(shù)列表。2.3 運(yùn)行結(jié)果參數(shù)組合的笛卡爾積當(dāng)存在多個(gè)[Params]成員時(shí)BenchmarkDotNet 會(huì)計(jì)算所有參數(shù)的笛卡爾積每一組取值組合都會(huì)構(gòu)成一個(gè)獨(dú)立的基準(zhǔn)用例。上述示例的實(shí)際運(yùn)行輸出如下見 IntroParams.md| Method | A | B | Mean | Error | StdDev | |---------- |---- |--- |---------:|--------:|--------:| | Benchmark | 100 | 10 | 115.3 ms | 0.13 ms | 0.12 ms | | Benchmark | 100 | 20 | 125.4 ms | 0.14 ms | 0.12 ms | | Benchmark | 200 | 10 | 215.5 ms | 0.19 ms | 0.18 ms | | Benchmark | 200 | 20 | 225.4 ms | 0.17 ms | 0.16 ms |可以看到結(jié)果表中A與B分別以獨(dú)立列呈現(xiàn)4 組組合2 × 2各占一行每組組合都擁有自己的 Mean/Error/StdDev 統(tǒng)計(jì)結(jié)果方便橫向比較參數(shù)變化帶來(lái)的性能差異。3. 源碼級(jí)解析ParamsAttribute 的真實(shí)定義要深入理解[Params]應(yīng)直接查看其定義。特性類位于 src/BenchmarkDotNet.Annotations/Attributes/ParamsAttribute.cs屬于BenchmarkDotNet.Annotations程序集即僅依賴特性聲明的最小程序集namespace BenchmarkDotNet.Attributes { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class ParamsAttribute : PriorityAttribute { public object?[] Values { get; protected set; } // CLS-Compliant Code requires a constructor without an array in the argument list public ParamsAttribute() Values []; public ParamsAttribute(params object?[]? values) Values values ?? [null]; // when users do Params(null) they mean one, null argument } }從源碼中可以提煉出幾個(gè)關(guān)鍵事實(shí)適用目標(biāo)受限AttributeUsage明確限制為AttributeTargets.Field | AttributeTargets.Property即只能標(biāo)注字段或?qū)傩圆荒軜?biāo)注方法或類參數(shù)值存儲(chǔ)所有值被放入object?[] Values因此值類型如int會(huì)被裝箱存儲(chǔ)[Params(null)]的語(yǔ)義當(dāng)用戶寫[Params(null)]時(shí)params機(jī)制會(huì)把null展開成一個(gè)包含單個(gè)null元素的數(shù)組而Values values ?? [null]則保證即使傳入整個(gè)數(shù)組為null也按一個(gè) null 參數(shù)處理從而讓基準(zhǔn)在參數(shù)值為null的情況下也能運(yùn)行繼承自PriorityAttribute[Params]與參數(shù)順序/優(yōu)先級(jí)體系相關(guān)PriorityAttribute用于控制同一類別內(nèi)參數(shù)的排列順序詳見下方第 6 節(jié)。4. 參數(shù)化背后的執(zhí)行模型從源碼結(jié)構(gòu)看參數(shù)化并不僅僅是把值塞進(jìn)屬性這么簡(jiǎn)單它貫穿了 BenchmarkDotNet 的用例構(gòu)建與代碼生成全鏈路參數(shù)定義src/BenchmarkDotNet/Parameters/ParameterDefinition.cs定義了參數(shù)的元信息名稱Name、是否靜態(tài)IsStatic、是否為方法實(shí)參IsArgument、類型ParameterType、類別內(nèi)優(yōu)先級(jí)PriorityInCategory。其中IsArgument用于區(qū)分賦值給成員的參數(shù)與作為方法調(diào)用實(shí)參的參數(shù)后者是[Arguments]特性的范疇參數(shù)實(shí)例與取值ParameterInstance.cs、ParameterInstances.cs、ParameterValues.cs等文件共同負(fù)責(zé)在基準(zhǔn)運(yùn)行時(shí)為每個(gè)組合創(chuàng)建參數(shù)實(shí)例并通過(guò)SmartParamBuilder生成對(duì)應(yīng)的代碼結(jié)果命名參數(shù)值會(huì)出現(xiàn)在結(jié)果文件名與結(jié)果列中ArrayDisplay.cs負(fù)責(zé)數(shù)組類參數(shù)的可讀展示。這意味著[Params]的值不僅參與基準(zhǔn)方法執(zhí)行還會(huì)影響基準(zhǔn)用例的標(biāo)識(shí)、產(chǎn)物命名與統(tǒng)計(jì)分組是框架用例 基準(zhǔn)方法 × 參數(shù)組合 × Job 配置這一核心模型中的重要一環(huán)。5. 合法性驗(yàn)證哪些寫法會(huì)被拒絕[Params]并非可以隨意使用。倉(cāng)庫(kù)中的 src/BenchmarkDotNet/Validators/ParamsValidator.cs 在基準(zhǔn)運(yùn)行前會(huì)對(duì)標(biāo)注了[Params]、[ParamsAllValues]、[ParamsSource]的成員做嚴(yán)格校驗(yàn)任何違規(guī)都會(huì)產(chǎn)生驗(yàn)證錯(cuò)誤TreatsWarningsAsErrors true直接阻止運(yùn)行。主要約束如下不可疊加使用同一成員上不能同時(shí)使用[Params]、[ParamsAllValues]、[ParamsSource]中的多個(gè)特性必須只用一個(gè)字段限制被標(biāo)注的字段不能是const常量字段也不能是readonly字段且必須是public屬性限制被標(biāo)注的屬性必須具有setter且 setter 必須是public源碼注釋特別說(shuō)明init-only setter 是允許的// An init-only setter is fine: the runnable assigns parameters through an object initializer.因?yàn)榭蚣芡ㄟ^(guò)對(duì)象初始化器賦值的機(jī)制與init訪問(wèn)器兼容靜態(tài)性字段或?qū)傩缘撵o態(tài)性不影響校驗(yàn)通過(guò)與否但I(xiàn)sStatic信息會(huì)被記錄在ParameterDefinition中用于代碼生成。這些規(guī)則的測(cè)試用例位于 tests/BenchmarkDotNet.Tests/Validators/ParamsValidatorTests.cs覆蓋了常量字段、readonly字段、多個(gè)特性疊加、私有 setter 等 359 行測(cè)試場(chǎng)景例如Const1Test、StaticReadonly1Test、FieldMultiple1Test、PrivateSetter1Test等是理解驗(yàn)證行為的第一手證據(jù)。6. 參數(shù)化家族ParamsSource 與 ParamsAllValues[Params]只是參數(shù)化家族的成員之一。特性定義中Values的屬性類型為object?[]而[Params(null)]的特殊語(yǔ)義表明這套體系對(duì)運(yùn)行時(shí)才知道的值另有安排——這正是其他特性的職責(zé)。完整參數(shù)化文檔見 docs/articles/features/parameterization.md相關(guān)示例還包括ParamsSource從屬性、靜態(tài)方法、其他類型的靜態(tài)方法甚至異步IAsyncEnumerable源動(dòng)態(tài)獲取參數(shù)值突破編譯時(shí)常量限制。示例還演示了帶[EnumeratorCancellation] CancellationToken的異步源可在枚舉過(guò)程中響應(yīng)基準(zhǔn)取消請(qǐng)求ParamsAllValues自動(dòng)枚舉枚舉類型enum的全部值或可空布爾型bool?的三個(gè)取值true/false/null無(wú)需手寫值列表ParamsPriority與ParamsAttribute繼承自PriorityAttribute的事實(shí)相呼應(yīng)用于控制參數(shù)在輸出中的排列順序。此外還有 IntroArguments向基準(zhǔn)方法傳入實(shí)參、IntroArgumentsSource、IntroArrayParam、IntroArgumentsPriority 等它們共同構(gòu)成完整的參數(shù)化與參數(shù)傳遞體系。7. 運(yùn)行與驗(yàn)證方式運(yùn)行基準(zhǔn)通過(guò)BenchmarkRunner.RunIntroParams()API 位于 src/BenchmarkDotNet/Running/BenchmarkRunner.cs 對(duì)應(yīng)目錄或 BenchmarkSwitcher 即可運(yùn)行該示例類運(yùn)行前框架會(huì)自動(dòng)執(zhí)行ParamsValidator等驗(yàn)證器違規(guī)寫法會(huì)直接報(bào)錯(cuò)而非靜默忽略倉(cāng)庫(kù)內(nèi)驗(yàn)證除 ParamsValidatorTests.cs 外tests/BenchmarkDotNet.Tests/ParameterInstanceTests.cs 與 tests/BenchmarkDotNet.Tests/ParamsSourceTests.cs 進(jìn)一步覆蓋了參數(shù)實(shí)例比較與動(dòng)態(tài)參數(shù)源的行為可作為理解內(nèi)部語(yǔ)義的參考。8. 小結(jié)[Params]是 BenchmarkDotNet 參數(shù)化基準(zhǔn)的基石它通過(guò)標(biāo)記字段/屬性 編譯時(shí)常量值列表的方式讓一個(gè)基準(zhǔn)方法自動(dòng)覆蓋多組輸入的笛卡爾積并以統(tǒng)一的表格呈現(xiàn)結(jié)果。配合源碼中的ParamsAttribute定義、ParamsValidator校驗(yàn)規(guī)則以及ParamsSource/ParamsAllValues/ParamsPriority家族特性你可以從固定單點(diǎn)測(cè)量升級(jí)為多維參數(shù)空間掃描更全面地評(píng)估算法與實(shí)現(xiàn)的實(shí)際性能表現(xiàn)?!久赓M(fèi)下載鏈接】BenchmarkDotNetPowerful .NET library for benchmarking項(xiàng)目地址: https://gitcode.com/gh_mirrors/be/BenchmarkDotNet創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考