LargeFileBenchmarks.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. using System.Text;
  2. using System.Text.Json;
  3. using BenchmarkDotNet.Attributes;
  4. using Apq.Cfg.Ini;
  5. using Apq.Cfg.Xml;
  6. using Apq.Cfg.Yaml;
  7. using Apq.Cfg.Toml;
  8. namespace Apq.Cfg.Benchmarks;
  9. /// <summary>
  10. /// 大文件加载性能基准测试
  11. /// 测试不同配置源加载大量配置项的性能
  12. /// </summary>
  13. [Config(typeof(BenchmarkConfig))]
  14. public class LargeFileBenchmarks : IDisposable
  15. {
  16. private readonly string _testDir;
  17. [Params(1000)]
  18. public int ItemCount { get; set; }
  19. private string _jsonPath = null!;
  20. private string _iniPath = null!;
  21. private string _xmlPath = null!;
  22. private string _yamlPath = null!;
  23. private string _tomlPath = null!;
  24. public LargeFileBenchmarks()
  25. {
  26. _testDir = Path.Combine(Path.GetTempPath(), $"ApqCfgBench_{Guid.NewGuid():N}");
  27. Directory.CreateDirectory(_testDir);
  28. }
  29. [GlobalSetup]
  30. public void Setup()
  31. {
  32. _jsonPath = Path.Combine(_testDir, $"large_{ItemCount}.json");
  33. _iniPath = Path.Combine(_testDir, $"large_{ItemCount}.ini");
  34. _xmlPath = Path.Combine(_testDir, $"large_{ItemCount}.xml");
  35. _yamlPath = Path.Combine(_testDir, $"large_{ItemCount}.yaml");
  36. _tomlPath = Path.Combine(_testDir, $"large_{ItemCount}.toml");
  37. GenerateJsonFile(_jsonPath, ItemCount);
  38. GenerateIniFile(_iniPath, ItemCount);
  39. GenerateXmlFile(_xmlPath, ItemCount);
  40. GenerateYamlFile(_yamlPath, ItemCount);
  41. GenerateTomlFile(_tomlPath, ItemCount);
  42. }
  43. [GlobalCleanup]
  44. public void Cleanup()
  45. {
  46. Dispose();
  47. }
  48. public void Dispose()
  49. {
  50. if (Directory.Exists(_testDir))
  51. {
  52. Directory.Delete(_testDir, true);
  53. }
  54. }
  55. #region 文件生成方法
  56. private static void GenerateJsonFile(string path, int count)
  57. {
  58. var data = new Dictionary<string, object>();
  59. for (int i = 0; i < count; i++)
  60. {
  61. var section = $"Section{i / 10}";
  62. if (!data.ContainsKey(section))
  63. {
  64. data[section] = new Dictionary<string, object>();
  65. }
  66. ((Dictionary<string, object>)data[section])[$"Key{i}"] = $"Value{i}";
  67. }
  68. File.WriteAllText(path, JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true }));
  69. }
  70. private static void GenerateIniFile(string path, int count)
  71. {
  72. var sb = new StringBuilder();
  73. var currentSection = -1;
  74. for (int i = 0; i < count; i++)
  75. {
  76. var section = i / 10;
  77. if (section != currentSection)
  78. {
  79. currentSection = section;
  80. sb.AppendLine($"[Section{section}]");
  81. }
  82. sb.AppendLine($"Key{i}=Value{i}");
  83. }
  84. File.WriteAllText(path, sb.ToString());
  85. }
  86. private static void GenerateXmlFile(string path, int count)
  87. {
  88. var sb = new StringBuilder();
  89. sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  90. sb.AppendLine("<configuration>");
  91. var currentSection = -1;
  92. for (int i = 0; i < count; i++)
  93. {
  94. var section = i / 10;
  95. if (section != currentSection)
  96. {
  97. if (currentSection >= 0)
  98. {
  99. sb.AppendLine($" </Section{currentSection}>");
  100. }
  101. currentSection = section;
  102. sb.AppendLine($" <Section{section}>");
  103. }
  104. sb.AppendLine($" <Key{i}>Value{i}</Key{i}>");
  105. }
  106. if (currentSection >= 0)
  107. {
  108. sb.AppendLine($" </Section{currentSection}>");
  109. }
  110. sb.AppendLine("</configuration>");
  111. File.WriteAllText(path, sb.ToString());
  112. }
  113. private static void GenerateYamlFile(string path, int count)
  114. {
  115. var sb = new StringBuilder();
  116. var currentSection = -1;
  117. for (int i = 0; i < count; i++)
  118. {
  119. var section = i / 10;
  120. if (section != currentSection)
  121. {
  122. currentSection = section;
  123. sb.AppendLine($"Section{section}:");
  124. }
  125. sb.AppendLine($" Key{i}: Value{i}");
  126. }
  127. File.WriteAllText(path, sb.ToString());
  128. }
  129. private static void GenerateTomlFile(string path, int count)
  130. {
  131. var sb = new StringBuilder();
  132. var currentSection = -1;
  133. for (int i = 0; i < count; i++)
  134. {
  135. var section = i / 10;
  136. if (section != currentSection)
  137. {
  138. currentSection = section;
  139. sb.AppendLine($"[Section{section}]");
  140. }
  141. sb.AppendLine($"Key{i} = \"Value{i}\"");
  142. }
  143. File.WriteAllText(path, sb.ToString());
  144. }
  145. #endregion
  146. #region 加载性能测试
  147. [Benchmark(Baseline = true)]
  148. [BenchmarkCategory("Load")]
  149. public void Json_Load()
  150. {
  151. using var cfg = new CfgBuilder()
  152. .AddJson(_jsonPath, level: 0, writeable: false)
  153. .Build();
  154. }
  155. [Benchmark]
  156. [BenchmarkCategory("Load")]
  157. public void Ini_Load()
  158. {
  159. using var cfg = new CfgBuilder()
  160. .AddIni(_iniPath, level: 0, writeable: false)
  161. .Build();
  162. }
  163. [Benchmark]
  164. [BenchmarkCategory("Load")]
  165. public void Xml_Load()
  166. {
  167. using var cfg = new CfgBuilder()
  168. .AddXml(_xmlPath, level: 0, writeable: false)
  169. .Build();
  170. }
  171. [Benchmark]
  172. [BenchmarkCategory("Load")]
  173. public void Yaml_Load()
  174. {
  175. using var cfg = new CfgBuilder()
  176. .AddYaml(_yamlPath, level: 0, writeable: false)
  177. .Build();
  178. }
  179. [Benchmark]
  180. [BenchmarkCategory("Load")]
  181. public void Toml_Load()
  182. {
  183. using var cfg = new CfgBuilder()
  184. .AddToml(_tomlPath, level: 0, writeable: false)
  185. .Build();
  186. }
  187. #endregion
  188. #region 加载后读取性能测试
  189. [Benchmark]
  190. [BenchmarkCategory("LoadAndRead")]
  191. public string? Json_LoadAndRead()
  192. {
  193. using var cfg = new CfgBuilder()
  194. .AddJson(_jsonPath, level: 0, writeable: false)
  195. .Build();
  196. return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}");
  197. }
  198. [Benchmark]
  199. [BenchmarkCategory("LoadAndRead")]
  200. public string? Ini_LoadAndRead()
  201. {
  202. using var cfg = new CfgBuilder()
  203. .AddIni(_iniPath, level: 0, writeable: false)
  204. .Build();
  205. return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}");
  206. }
  207. [Benchmark]
  208. [BenchmarkCategory("LoadAndRead")]
  209. public string? Xml_LoadAndRead()
  210. {
  211. using var cfg = new CfgBuilder()
  212. .AddXml(_xmlPath, level: 0, writeable: false)
  213. .Build();
  214. return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}");
  215. }
  216. [Benchmark]
  217. [BenchmarkCategory("LoadAndRead")]
  218. public string? Yaml_LoadAndRead()
  219. {
  220. using var cfg = new CfgBuilder()
  221. .AddYaml(_yamlPath, level: 0, writeable: false)
  222. .Build();
  223. return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}");
  224. }
  225. [Benchmark]
  226. [BenchmarkCategory("LoadAndRead")]
  227. public string? Toml_LoadAndRead()
  228. {
  229. using var cfg = new CfgBuilder()
  230. .AddToml(_tomlPath, level: 0, writeable: false)
  231. .Build();
  232. return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}");
  233. }
  234. #endregion
  235. }