using System.Text; using System.Text.Json; using BenchmarkDotNet.Attributes; using Apq.Cfg.Ini; using Apq.Cfg.Xml; using Apq.Cfg.Yaml; using Apq.Cfg.Toml; namespace Apq.Cfg.Benchmarks; /// /// 大文件加载性能基准测试 /// 测试不同配置源加载大量配置项的性能 /// [Config(typeof(BenchmarkConfig))] public class LargeFileBenchmarks : IDisposable { private readonly string _testDir; [Params(1000)] public int ItemCount { get; set; } private string _jsonPath = null!; private string _iniPath = null!; private string _xmlPath = null!; private string _yamlPath = null!; private string _tomlPath = null!; public LargeFileBenchmarks() { _testDir = Path.Combine(Path.GetTempPath(), $"ApqCfgBench_{Guid.NewGuid():N}"); Directory.CreateDirectory(_testDir); } [GlobalSetup] public void Setup() { _jsonPath = Path.Combine(_testDir, $"large_{ItemCount}.json"); _iniPath = Path.Combine(_testDir, $"large_{ItemCount}.ini"); _xmlPath = Path.Combine(_testDir, $"large_{ItemCount}.xml"); _yamlPath = Path.Combine(_testDir, $"large_{ItemCount}.yaml"); _tomlPath = Path.Combine(_testDir, $"large_{ItemCount}.toml"); GenerateJsonFile(_jsonPath, ItemCount); GenerateIniFile(_iniPath, ItemCount); GenerateXmlFile(_xmlPath, ItemCount); GenerateYamlFile(_yamlPath, ItemCount); GenerateTomlFile(_tomlPath, ItemCount); } [GlobalCleanup] public void Cleanup() { Dispose(); } public void Dispose() { if (Directory.Exists(_testDir)) { Directory.Delete(_testDir, true); } } #region 文件生成方法 private static void GenerateJsonFile(string path, int count) { var data = new Dictionary(); for (int i = 0; i < count; i++) { var section = $"Section{i / 10}"; if (!data.ContainsKey(section)) { data[section] = new Dictionary(); } ((Dictionary)data[section])[$"Key{i}"] = $"Value{i}"; } File.WriteAllText(path, JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true })); } private static void GenerateIniFile(string path, int count) { var sb = new StringBuilder(); var currentSection = -1; for (int i = 0; i < count; i++) { var section = i / 10; if (section != currentSection) { currentSection = section; sb.AppendLine($"[Section{section}]"); } sb.AppendLine($"Key{i}=Value{i}"); } File.WriteAllText(path, sb.ToString()); } private static void GenerateXmlFile(string path, int count) { var sb = new StringBuilder(); sb.AppendLine(""); sb.AppendLine(""); var currentSection = -1; for (int i = 0; i < count; i++) { var section = i / 10; if (section != currentSection) { if (currentSection >= 0) { sb.AppendLine($" "); } currentSection = section; sb.AppendLine($" "); } sb.AppendLine($" Value{i}"); } if (currentSection >= 0) { sb.AppendLine($" "); } sb.AppendLine(""); File.WriteAllText(path, sb.ToString()); } private static void GenerateYamlFile(string path, int count) { var sb = new StringBuilder(); var currentSection = -1; for (int i = 0; i < count; i++) { var section = i / 10; if (section != currentSection) { currentSection = section; sb.AppendLine($"Section{section}:"); } sb.AppendLine($" Key{i}: Value{i}"); } File.WriteAllText(path, sb.ToString()); } private static void GenerateTomlFile(string path, int count) { var sb = new StringBuilder(); var currentSection = -1; for (int i = 0; i < count; i++) { var section = i / 10; if (section != currentSection) { currentSection = section; sb.AppendLine($"[Section{section}]"); } sb.AppendLine($"Key{i} = \"Value{i}\""); } File.WriteAllText(path, sb.ToString()); } #endregion #region 加载性能测试 [Benchmark(Baseline = true)] [BenchmarkCategory("Load")] public void Json_Load() { using var cfg = new CfgBuilder() .AddJson(_jsonPath, level: 0, writeable: false) .Build(); } [Benchmark] [BenchmarkCategory("Load")] public void Ini_Load() { using var cfg = new CfgBuilder() .AddIni(_iniPath, level: 0, writeable: false) .Build(); } [Benchmark] [BenchmarkCategory("Load")] public void Xml_Load() { using var cfg = new CfgBuilder() .AddXml(_xmlPath, level: 0, writeable: false) .Build(); } [Benchmark] [BenchmarkCategory("Load")] public void Yaml_Load() { using var cfg = new CfgBuilder() .AddYaml(_yamlPath, level: 0, writeable: false) .Build(); } [Benchmark] [BenchmarkCategory("Load")] public void Toml_Load() { using var cfg = new CfgBuilder() .AddToml(_tomlPath, level: 0, writeable: false) .Build(); } #endregion #region 加载后读取性能测试 [Benchmark] [BenchmarkCategory("LoadAndRead")] public string? Json_LoadAndRead() { using var cfg = new CfgBuilder() .AddJson(_jsonPath, level: 0, writeable: false) .Build(); return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}"); } [Benchmark] [BenchmarkCategory("LoadAndRead")] public string? Ini_LoadAndRead() { using var cfg = new CfgBuilder() .AddIni(_iniPath, level: 0, writeable: false) .Build(); return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}"); } [Benchmark] [BenchmarkCategory("LoadAndRead")] public string? Xml_LoadAndRead() { using var cfg = new CfgBuilder() .AddXml(_xmlPath, level: 0, writeable: false) .Build(); return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}"); } [Benchmark] [BenchmarkCategory("LoadAndRead")] public string? Yaml_LoadAndRead() { using var cfg = new CfgBuilder() .AddYaml(_yamlPath, level: 0, writeable: false) .Build(); return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}"); } [Benchmark] [BenchmarkCategory("LoadAndRead")] public string? Toml_LoadAndRead() { using var cfg = new CfgBuilder() .AddToml(_tomlPath, level: 0, writeable: false) .Build(); return cfg.Get($"Section{ItemCount / 20}:Key{ItemCount / 2}"); } #endregion }