TypeConversionBenchmarks.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. using BenchmarkDotNet.Attributes;
  2. namespace Apq.Cfg.Benchmarks;
  3. /// <summary>
  4. /// 类型转换性能基准测试
  5. /// 测试 Get&lt;T&gt; 不同类型转换的性能开销
  6. /// </summary>
  7. [Config(typeof(BenchmarkConfig))]
  8. public class TypeConversionBenchmarks : IDisposable
  9. {
  10. private readonly string _testDir;
  11. private ICfgRoot _cfg = null!;
  12. public TypeConversionBenchmarks()
  13. {
  14. _testDir = Path.Combine(Path.GetTempPath(), $"ApqCfgBench_{Guid.NewGuid():N}");
  15. Directory.CreateDirectory(_testDir);
  16. }
  17. [GlobalSetup]
  18. public void Setup()
  19. {
  20. var jsonPath = Path.Combine(_testDir, "config.json");
  21. File.WriteAllText(jsonPath, """
  22. {
  23. "Types": {
  24. "String": "HelloWorld",
  25. "LongString": "This is a very long string value that contains many characters to test string handling performance in the configuration system",
  26. "Int": "12345",
  27. "Long": "9223372036854775807",
  28. "Double": "3.14159265358979",
  29. "Decimal": "12345.6789012345",
  30. "Bool": "true",
  31. "BoolFalse": "false",
  32. "Guid": "550e8400-e29b-41d4-a716-446655440000",
  33. "DateTime": "2024-12-24T12:00:00",
  34. "Enum": "Warning",
  35. "NullableInt": "42",
  36. "EmptyString": "",
  37. "Whitespace": " ",
  38. "Unicode": "你好世界🌍",
  39. "SpecialChars": "Hello:World=Test\"Quote'Single"
  40. }
  41. }
  42. """);
  43. _cfg = new CfgBuilder()
  44. .AddJson(jsonPath, level: 0, writeable: false)
  45. .Build();
  46. }
  47. [GlobalCleanup]
  48. public void Cleanup()
  49. {
  50. Dispose();
  51. }
  52. public void Dispose()
  53. {
  54. _cfg?.Dispose();
  55. if (Directory.Exists(_testDir))
  56. {
  57. Directory.Delete(_testDir, true);
  58. }
  59. }
  60. #region 基础类型转换
  61. /// <summary>
  62. /// 获取字符串(无转换,作为基准)
  63. /// </summary>
  64. [Benchmark(Baseline = true)]
  65. [BenchmarkCategory("BasicTypes")]
  66. public string? Get_String()
  67. {
  68. return _cfg.Get("Types:String");
  69. }
  70. /// <summary>
  71. /// 获取字符串(泛型方式)
  72. /// </summary>
  73. [Benchmark]
  74. [BenchmarkCategory("BasicTypes")]
  75. public string? Get_String_Generic()
  76. {
  77. return _cfg.Get<string>("Types:String");
  78. }
  79. /// <summary>
  80. /// 获取整数
  81. /// </summary>
  82. [Benchmark]
  83. [BenchmarkCategory("BasicTypes")]
  84. public int Get_Int()
  85. {
  86. return _cfg.Get<int>("Types:Int");
  87. }
  88. /// <summary>
  89. /// 获取长整数
  90. /// </summary>
  91. [Benchmark]
  92. [BenchmarkCategory("BasicTypes")]
  93. public long Get_Long()
  94. {
  95. return _cfg.Get<long>("Types:Long");
  96. }
  97. /// <summary>
  98. /// 获取双精度浮点数
  99. /// </summary>
  100. [Benchmark]
  101. [BenchmarkCategory("BasicTypes")]
  102. public double Get_Double()
  103. {
  104. return _cfg.Get<double>("Types:Double");
  105. }
  106. /// <summary>
  107. /// 获取十进制数
  108. /// </summary>
  109. [Benchmark]
  110. [BenchmarkCategory("BasicTypes")]
  111. public decimal Get_Decimal()
  112. {
  113. return _cfg.Get<decimal>("Types:Decimal");
  114. }
  115. /// <summary>
  116. /// 获取布尔值
  117. /// </summary>
  118. [Benchmark]
  119. [BenchmarkCategory("BasicTypes")]
  120. public bool Get_Bool()
  121. {
  122. return _cfg.Get<bool>("Types:Bool");
  123. }
  124. #endregion
  125. #region 复杂类型转换
  126. /// <summary>
  127. /// 获取 Guid
  128. /// </summary>
  129. [Benchmark]
  130. [BenchmarkCategory("ComplexTypes")]
  131. public Guid Get_Guid()
  132. {
  133. return _cfg.Get<Guid>("Types:Guid");
  134. }
  135. /// <summary>
  136. /// 获取 DateTime
  137. /// </summary>
  138. [Benchmark]
  139. [BenchmarkCategory("ComplexTypes")]
  140. public DateTime Get_DateTime()
  141. {
  142. return _cfg.Get<DateTime>("Types:DateTime");
  143. }
  144. /// <summary>
  145. /// 获取枚举值
  146. /// </summary>
  147. [Benchmark]
  148. [BenchmarkCategory("ComplexTypes")]
  149. public LogLevel Get_Enum()
  150. {
  151. return _cfg.Get<LogLevel>("Types:Enum");
  152. }
  153. /// <summary>
  154. /// 获取可空整数
  155. /// </summary>
  156. [Benchmark]
  157. [BenchmarkCategory("ComplexTypes")]
  158. public int? Get_NullableInt()
  159. {
  160. return _cfg.Get<int?>("Types:NullableInt");
  161. }
  162. #endregion
  163. #region 批量类型转换
  164. /// <summary>
  165. /// 批量获取整数
  166. /// </summary>
  167. [Benchmark]
  168. [BenchmarkCategory("Batch")]
  169. public void Get_Int_Multiple()
  170. {
  171. for (int i = 0; i < 1000; i++)
  172. {
  173. _ = _cfg.Get<int>("Types:Int");
  174. }
  175. }
  176. /// <summary>
  177. /// 批量获取布尔值
  178. /// </summary>
  179. [Benchmark]
  180. [BenchmarkCategory("Batch")]
  181. public void Get_Bool_Multiple()
  182. {
  183. for (int i = 0; i < 1000; i++)
  184. {
  185. _ = _cfg.Get<bool>("Types:Bool");
  186. }
  187. }
  188. /// <summary>
  189. /// 批量获取双精度浮点数
  190. /// </summary>
  191. [Benchmark]
  192. [BenchmarkCategory("Batch")]
  193. public void Get_Double_Multiple()
  194. {
  195. for (int i = 0; i < 1000; i++)
  196. {
  197. _ = _cfg.Get<double>("Types:Double");
  198. }
  199. }
  200. /// <summary>
  201. /// 批量获取字符串
  202. /// </summary>
  203. [Benchmark]
  204. [BenchmarkCategory("Batch")]
  205. public void Get_String_Multiple()
  206. {
  207. for (int i = 0; i < 1000; i++)
  208. {
  209. _ = _cfg.Get("Types:String");
  210. }
  211. }
  212. #endregion
  213. #region 特殊值处理
  214. /// <summary>
  215. /// 获取长字符串
  216. /// </summary>
  217. [Benchmark]
  218. [BenchmarkCategory("SpecialValues")]
  219. public string? Get_LongString()
  220. {
  221. return _cfg.Get("Types:LongString");
  222. }
  223. /// <summary>
  224. /// 获取 Unicode 字符串
  225. /// </summary>
  226. [Benchmark]
  227. [BenchmarkCategory("SpecialValues")]
  228. public string? Get_Unicode()
  229. {
  230. return _cfg.Get("Types:Unicode");
  231. }
  232. /// <summary>
  233. /// 获取包含特殊字符的字符串
  234. /// </summary>
  235. [Benchmark]
  236. [BenchmarkCategory("SpecialValues")]
  237. public string? Get_SpecialChars()
  238. {
  239. return _cfg.Get("Types:SpecialChars");
  240. }
  241. /// <summary>
  242. /// 获取空字符串
  243. /// </summary>
  244. [Benchmark]
  245. [BenchmarkCategory("SpecialValues")]
  246. public string? Get_EmptyString()
  247. {
  248. return _cfg.Get("Types:EmptyString");
  249. }
  250. #endregion
  251. #region TryGet 扩展方法
  252. /// <summary>
  253. /// TryGet 成功场景
  254. /// </summary>
  255. [Benchmark]
  256. [BenchmarkCategory("Extensions")]
  257. public bool TryGet_Success()
  258. {
  259. return _cfg.TryGet<int>("Types:Int", out _);
  260. }
  261. /// <summary>
  262. /// TryGet 失败场景
  263. /// </summary>
  264. [Benchmark]
  265. [BenchmarkCategory("Extensions")]
  266. public bool TryGet_Failure()
  267. {
  268. return _cfg.TryGet<int>("Types:NonExistent", out _);
  269. }
  270. /// <summary>
  271. /// GetRequired 成功场景
  272. /// </summary>
  273. [Benchmark]
  274. [BenchmarkCategory("Extensions")]
  275. public int GetRequired_Success()
  276. {
  277. return _cfg.GetRequired<int>("Types:Int");
  278. }
  279. /// <summary>
  280. /// GetOrDefault 存在键场景
  281. /// </summary>
  282. [Benchmark]
  283. [BenchmarkCategory("Extensions")]
  284. public int GetOrDefault_ExistingKey()
  285. {
  286. return _cfg.GetOrDefault("Types:Int", 0);
  287. }
  288. /// <summary>
  289. /// GetOrDefault 不存在键场景
  290. /// </summary>
  291. [Benchmark]
  292. [BenchmarkCategory("Extensions")]
  293. public int GetOrDefault_NonExistingKey()
  294. {
  295. return _cfg.GetOrDefault("Types:NonExistent", 100);
  296. }
  297. #endregion
  298. #region 混合类型操作
  299. /// <summary>
  300. /// 混合读取多种类型
  301. /// </summary>
  302. [Benchmark]
  303. [BenchmarkCategory("Mixed")]
  304. public void Get_MixedTypes()
  305. {
  306. for (int i = 0; i < 100; i++)
  307. {
  308. _ = _cfg.Get("Types:String");
  309. _ = _cfg.Get<int>("Types:Int");
  310. _ = _cfg.Get<bool>("Types:Bool");
  311. _ = _cfg.Get<double>("Types:Double");
  312. _ = _cfg.Get<long>("Types:Long");
  313. }
  314. }
  315. #endregion
  316. }
  317. /// <summary>
  318. /// 用于枚举转换测试的日志级别
  319. /// </summary>
  320. public enum LogLevel
  321. {
  322. Debug,
  323. Info,
  324. Warning,
  325. Error,
  326. Fatal
  327. }