SaveBenchmarks.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. using BenchmarkDotNet.Attributes;
  2. using Apq.Cfg.Ini;
  3. using Apq.Cfg.Xml;
  4. using Apq.Cfg.Yaml;
  5. using Apq.Cfg.Toml;
  6. namespace Apq.Cfg.Benchmarks;
  7. /// <summary>
  8. /// 持久化性能基准测试
  9. /// 测试 SaveAsync 在不同数据量下的性能
  10. /// </summary>
  11. [Config(typeof(BenchmarkConfig))]
  12. public class SaveBenchmarks : IDisposable
  13. {
  14. private readonly string _testDir;
  15. private ICfgRoot _jsonCfg = null!;
  16. private ICfgRoot _iniCfg = null!;
  17. private ICfgRoot _xmlCfg = null!;
  18. private ICfgRoot _yamlCfg = null!;
  19. private ICfgRoot _tomlCfg = null!;
  20. private string _jsonPath = null!;
  21. private string _iniPath = null!;
  22. private string _xmlPath = null!;
  23. private string _yamlPath = null!;
  24. private string _tomlPath = null!;
  25. [Params(50)]
  26. public int ChangeCount { get; set; }
  27. public SaveBenchmarks()
  28. {
  29. _testDir = Path.Combine(Path.GetTempPath(), $"ApqCfgBench_{Guid.NewGuid():N}");
  30. Directory.CreateDirectory(_testDir);
  31. }
  32. [GlobalSetup]
  33. public void Setup()
  34. {
  35. // 创建 JSON 配置文件
  36. _jsonPath = Path.Combine(_testDir, "config.json");
  37. File.WriteAllText(_jsonPath, """
  38. {
  39. "App": {
  40. "Name": "BenchmarkApp"
  41. }
  42. }
  43. """);
  44. _jsonCfg = new CfgBuilder()
  45. .AddJson(_jsonPath, level: 0, writeable: true, isPrimaryWriter: true)
  46. .Build();
  47. // 创建 INI 配置文件
  48. _iniPath = Path.Combine(_testDir, "config.ini");
  49. File.WriteAllText(_iniPath, """
  50. [App]
  51. Name=BenchmarkApp
  52. """);
  53. _iniCfg = new CfgBuilder()
  54. .AddIni(_iniPath, level: 0, writeable: true, isPrimaryWriter: true)
  55. .Build();
  56. // 创建 XML 配置文件
  57. _xmlPath = Path.Combine(_testDir, "config.xml");
  58. File.WriteAllText(_xmlPath, """
  59. <?xml version="1.0" encoding="utf-8"?>
  60. <configuration>
  61. <App>
  62. <Name>BenchmarkApp</Name>
  63. </App>
  64. </configuration>
  65. """);
  66. _xmlCfg = new CfgBuilder()
  67. .AddXml(_xmlPath, level: 0, writeable: true, isPrimaryWriter: true)
  68. .Build();
  69. // 创建 YAML 配置文件
  70. _yamlPath = Path.Combine(_testDir, "config.yaml");
  71. File.WriteAllText(_yamlPath, """
  72. App:
  73. Name: BenchmarkApp
  74. """);
  75. _yamlCfg = new CfgBuilder()
  76. .AddYaml(_yamlPath, level: 0, writeable: true, isPrimaryWriter: true)
  77. .Build();
  78. // 创建 TOML 配置文件
  79. _tomlPath = Path.Combine(_testDir, "config.toml");
  80. File.WriteAllText(_tomlPath, """
  81. [App]
  82. Name = "BenchmarkApp"
  83. """);
  84. _tomlCfg = new CfgBuilder()
  85. .AddToml(_tomlPath, level: 0, writeable: true, isPrimaryWriter: true)
  86. .Build();
  87. }
  88. [IterationSetup]
  89. public void IterationSetup()
  90. {
  91. // 每次迭代前重置配置文件,确保测试一致性
  92. File.WriteAllText(_jsonPath, """
  93. {
  94. "App": {
  95. "Name": "BenchmarkApp"
  96. }
  97. }
  98. """);
  99. File.WriteAllText(_iniPath, """
  100. [App]
  101. Name=BenchmarkApp
  102. """);
  103. File.WriteAllText(_xmlPath, """
  104. <?xml version="1.0" encoding="utf-8"?>
  105. <configuration>
  106. <App>
  107. <Name>BenchmarkApp</Name>
  108. </App>
  109. </configuration>
  110. """);
  111. File.WriteAllText(_yamlPath, """
  112. App:
  113. Name: BenchmarkApp
  114. """);
  115. File.WriteAllText(_tomlPath, """
  116. [App]
  117. Name = "BenchmarkApp"
  118. """);
  119. }
  120. [GlobalCleanup]
  121. public void Cleanup()
  122. {
  123. Dispose();
  124. }
  125. public void Dispose()
  126. {
  127. _jsonCfg?.Dispose();
  128. _iniCfg?.Dispose();
  129. _xmlCfg?.Dispose();
  130. _yamlCfg?.Dispose();
  131. _tomlCfg?.Dispose();
  132. if (Directory.Exists(_testDir))
  133. {
  134. Directory.Delete(_testDir, true);
  135. }
  136. }
  137. #region SaveAsync 性能测试
  138. [Benchmark(Baseline = true)]
  139. [BenchmarkCategory("Save")]
  140. public async Task Json_Save()
  141. {
  142. for (int i = 0; i < ChangeCount; i++)
  143. {
  144. _jsonCfg.Set($"Data:Key{i}", $"Value{i}");
  145. }
  146. await _jsonCfg.SaveAsync();
  147. }
  148. [Benchmark]
  149. [BenchmarkCategory("Save")]
  150. public async Task Ini_Save()
  151. {
  152. for (int i = 0; i < ChangeCount; i++)
  153. {
  154. _iniCfg.Set($"Data:Key{i}", $"Value{i}");
  155. }
  156. await _iniCfg.SaveAsync();
  157. }
  158. [Benchmark]
  159. [BenchmarkCategory("Save")]
  160. public async Task Xml_Save()
  161. {
  162. for (int i = 0; i < ChangeCount; i++)
  163. {
  164. _xmlCfg.Set($"Data:Key{i}", $"Value{i}");
  165. }
  166. await _xmlCfg.SaveAsync();
  167. }
  168. [Benchmark]
  169. [BenchmarkCategory("Save")]
  170. public async Task Yaml_Save()
  171. {
  172. for (int i = 0; i < ChangeCount; i++)
  173. {
  174. _yamlCfg.Set($"Data:Key{i}", $"Value{i}");
  175. }
  176. await _yamlCfg.SaveAsync();
  177. }
  178. [Benchmark]
  179. [BenchmarkCategory("Save")]
  180. public async Task Toml_Save()
  181. {
  182. for (int i = 0; i < ChangeCount; i++)
  183. {
  184. _tomlCfg.Set($"Data:Key{i}", $"Value{i}");
  185. }
  186. await _tomlCfg.SaveAsync();
  187. }
  188. #endregion
  189. #region 大值保存测试
  190. [Benchmark]
  191. [BenchmarkCategory("SaveLargeValue")]
  192. public async Task Json_SaveLargeValue()
  193. {
  194. var largeValue = new string('X', 10000);
  195. for (int i = 0; i < ChangeCount / 10; i++)
  196. {
  197. _jsonCfg.Set($"LargeData:Key{i}", largeValue);
  198. }
  199. await _jsonCfg.SaveAsync();
  200. }
  201. [Benchmark]
  202. [BenchmarkCategory("SaveLargeValue")]
  203. public async Task Ini_SaveLargeValue()
  204. {
  205. var largeValue = new string('X', 10000);
  206. for (int i = 0; i < ChangeCount / 10; i++)
  207. {
  208. _iniCfg.Set($"LargeData:Key{i}", largeValue);
  209. }
  210. await _iniCfg.SaveAsync();
  211. }
  212. #endregion
  213. #region 频繁保存测试
  214. [Benchmark]
  215. [BenchmarkCategory("FrequentSave")]
  216. public async Task Json_FrequentSave()
  217. {
  218. for (int i = 0; i < ChangeCount; i++)
  219. {
  220. _jsonCfg.Set($"Frequent:Key{i}", $"Value{i}");
  221. if (i % 10 == 0)
  222. {
  223. await _jsonCfg.SaveAsync();
  224. }
  225. }
  226. await _jsonCfg.SaveAsync();
  227. }
  228. [Benchmark]
  229. [BenchmarkCategory("FrequentSave")]
  230. public async Task Ini_FrequentSave()
  231. {
  232. for (int i = 0; i < ChangeCount; i++)
  233. {
  234. _iniCfg.Set($"Frequent:Key{i}", $"Value{i}");
  235. if (i % 10 == 0)
  236. {
  237. await _iniCfg.SaveAsync();
  238. }
  239. }
  240. await _iniCfg.SaveAsync();
  241. }
  242. #endregion
  243. }