MicrosoftConfigBenchmarks.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. using BenchmarkDotNet.Attributes;
  2. using Microsoft.Extensions.Configuration;
  3. namespace Apq.Cfg.Benchmarks;
  4. /// <summary>
  5. /// Microsoft Configuration 转换性能基准测试
  6. /// 测试 ToMicrosoftConfiguration 和 ConfigChanges 的性能
  7. /// </summary>
  8. [Config(typeof(BenchmarkConfig))]
  9. public class MicrosoftConfigBenchmarks : IDisposable
  10. {
  11. private readonly string _testDir;
  12. private ICfgRoot _cfg = null!;
  13. private IConfigurationRoot _msConfig = null!;
  14. public MicrosoftConfigBenchmarks()
  15. {
  16. _testDir = Path.Combine(Path.GetTempPath(), $"ApqCfgBench_{Guid.NewGuid():N}");
  17. Directory.CreateDirectory(_testDir);
  18. }
  19. [GlobalSetup]
  20. public void Setup()
  21. {
  22. var jsonPath = Path.Combine(_testDir, "config.json");
  23. // 生成包含多层嵌套的配置
  24. File.WriteAllText(jsonPath, """
  25. {
  26. "Database": {
  27. "Host": "localhost",
  28. "Port": 5432,
  29. "Name": "testdb",
  30. "Connection": {
  31. "Timeout": 30,
  32. "MaxRetries": 3
  33. }
  34. },
  35. "App": {
  36. "Name": "BenchmarkApp",
  37. "Version": "1.0.0",
  38. "Settings": {
  39. "MaxRetries": 3,
  40. "Enabled": true
  41. }
  42. },
  43. "Logging": {
  44. "Level": "Info",
  45. "Output": "Console"
  46. }
  47. }
  48. """);
  49. _cfg = new CfgBuilder()
  50. .AddJson(jsonPath, level: 0, writeable: true, isPrimaryWriter: true)
  51. .Build();
  52. // 预先创建一个 Microsoft Configuration 用于读取测试
  53. _msConfig = _cfg.ToMicrosoftConfiguration();
  54. }
  55. [GlobalCleanup]
  56. public void Cleanup()
  57. {
  58. Dispose();
  59. }
  60. public void Dispose()
  61. {
  62. _cfg?.Dispose();
  63. if (Directory.Exists(_testDir))
  64. {
  65. Directory.Delete(_testDir, true);
  66. }
  67. }
  68. #region ToMicrosoftConfiguration 性能测试
  69. /// <summary>
  70. /// 转换为 Microsoft Configuration(静态快照)
  71. /// </summary>
  72. [Benchmark(Baseline = true)]
  73. [BenchmarkCategory("ToMsConfig")]
  74. public IConfigurationRoot ToMicrosoftConfiguration_Static()
  75. {
  76. return _cfg.ToMicrosoftConfiguration();
  77. }
  78. /// <summary>
  79. /// 转换为支持动态重载的 Microsoft Configuration
  80. /// </summary>
  81. [Benchmark]
  82. [BenchmarkCategory("ToMsConfig")]
  83. public IConfigurationRoot ToMicrosoftConfiguration_Dynamic()
  84. {
  85. return _cfg.ToMicrosoftConfiguration(new Apq.Cfg.Changes.DynamicReloadOptions());
  86. }
  87. /// <summary>
  88. /// 多次转换(测试缓存效果)
  89. /// </summary>
  90. [Benchmark]
  91. [BenchmarkCategory("ToMsConfig")]
  92. public void ToMicrosoftConfiguration_Multiple()
  93. {
  94. for (int i = 0; i < 100; i++)
  95. {
  96. _ = _cfg.ToMicrosoftConfiguration();
  97. }
  98. }
  99. #endregion
  100. #region Microsoft Configuration 读取性能对比
  101. /// <summary>
  102. /// 通过 ICfgRoot 读取
  103. /// </summary>
  104. [Benchmark]
  105. [BenchmarkCategory("ReadComparison")]
  106. public string? Read_ViaApqCfg()
  107. {
  108. return _cfg.Get("Database:Host");
  109. }
  110. /// <summary>
  111. /// 通过 IConfigurationRoot 读取
  112. /// </summary>
  113. [Benchmark]
  114. [BenchmarkCategory("ReadComparison")]
  115. public string? Read_ViaMsConfig()
  116. {
  117. return _msConfig["Database:Host"];
  118. }
  119. /// <summary>
  120. /// 批量读取对比 - ICfgRoot
  121. /// </summary>
  122. [Benchmark]
  123. [BenchmarkCategory("ReadComparison")]
  124. public void BatchRead_ViaApqCfg()
  125. {
  126. for (int i = 0; i < 100; i++)
  127. {
  128. _ = _cfg.Get("Database:Host");
  129. _ = _cfg.Get("Database:Port");
  130. _ = _cfg.Get("App:Name");
  131. }
  132. }
  133. /// <summary>
  134. /// 批量读取对比 - IConfigurationRoot
  135. /// </summary>
  136. [Benchmark]
  137. [BenchmarkCategory("ReadComparison")]
  138. public void BatchRead_ViaMsConfig()
  139. {
  140. for (int i = 0; i < 100; i++)
  141. {
  142. _ = _msConfig["Database:Host"];
  143. _ = _msConfig["Database:Port"];
  144. _ = _msConfig["App:Name"];
  145. }
  146. }
  147. #endregion
  148. #region ConfigChanges 订阅性能测试
  149. /// <summary>
  150. /// 订阅配置变更
  151. /// </summary>
  152. [Benchmark]
  153. [BenchmarkCategory("ConfigChanges")]
  154. public void Subscribe_ConfigChanges()
  155. {
  156. using var subscription = _cfg.ConfigChanges.Subscribe(_ => { });
  157. }
  158. /// <summary>
  159. /// 订阅并触发变更
  160. /// </summary>
  161. [Benchmark]
  162. [BenchmarkCategory("ConfigChanges")]
  163. public void Subscribe_AndTriggerChange()
  164. {
  165. int changeCount = 0;
  166. using var subscription = _cfg.ConfigChanges.Subscribe(_ => changeCount++);
  167. // 触发变更
  168. _cfg.Set("Temp:Key", "Value");
  169. }
  170. /// <summary>
  171. /// 多订阅者场景
  172. /// </summary>
  173. [Benchmark]
  174. [BenchmarkCategory("ConfigChanges")]
  175. public void MultipleSubscribers()
  176. {
  177. var subscriptions = new List<IDisposable>();
  178. try
  179. {
  180. // 创建 10 个订阅者
  181. for (int i = 0; i < 10; i++)
  182. {
  183. subscriptions.Add(_cfg.ConfigChanges.Subscribe(_ => { }));
  184. }
  185. // 触发变更
  186. _cfg.Set("Temp:MultiKey", "Value");
  187. }
  188. finally
  189. {
  190. foreach (var sub in subscriptions)
  191. {
  192. sub.Dispose();
  193. }
  194. }
  195. }
  196. #endregion
  197. }