using BenchmarkDotNet.Attributes;
namespace Apq.Cfg.Benchmarks;
///
/// 键路径深度性能基准测试
/// 测试不同深度的键路径解析性能
///
[Config(typeof(BenchmarkConfig))]
public class KeyPathBenchmarks : IDisposable
{
private readonly string _testDir;
private ICfgRoot _cfg = null!;
[Params(5)]
public int PathDepth { get; set; }
private string _deepKey = null!;
private string _nonExistentDeepKey = null!;
public KeyPathBenchmarks()
{
_testDir = Path.Combine(Path.GetTempPath(), $"ApqCfgBench_{Guid.NewGuid():N}");
Directory.CreateDirectory(_testDir);
}
[GlobalSetup]
public void Setup()
{
var jsonPath = Path.Combine(_testDir, "config.json");
// 生成深层嵌套的 JSON 结构
var content = GenerateNestedJson(PathDepth);
File.WriteAllText(jsonPath, content);
_cfg = new CfgBuilder()
.AddJson(jsonPath, level: 0, writeable: true, isPrimaryWriter: true)
.Build();
// 生成对应深度的键路径
_deepKey = GenerateKeyPath(PathDepth);
_nonExistentDeepKey = GenerateKeyPath(PathDepth) + ":NonExistent";
}
private static string GenerateNestedJson(int depth)
{
if (depth <= 0) return "{}";
var indent = new string(' ', 2);
var result = "{\n";
void AddLevel(int currentDepth, int indentLevel)
{
var currentIndent = new string(' ', indentLevel * 2);
var levelName = $"Level{currentDepth}";
if (currentDepth == depth)
{
result += $"{currentIndent}\"{levelName}\": {{\n";
result += $"{currentIndent} \"Value\": \"DeepValue\",\n";
result += $"{currentIndent} \"Number\": 12345,\n";
result += $"{currentIndent} \"Boolean\": true\n";
result += $"{currentIndent}}}";
}
else
{
result += $"{currentIndent}\"{levelName}\": {{\n";
AddLevel(currentDepth + 1, indentLevel + 1);
result += $"\n{currentIndent}}}";
}
}
AddLevel(1, 1);
result += "\n}";
return result;
}
private static string GenerateKeyPath(int depth)
{
var parts = new string[depth + 1];
for (int i = 0; i < depth; i++)
{
parts[i] = $"Level{i + 1}";
}
parts[depth] = "Value";
return string.Join(":", parts);
}
[GlobalCleanup]
public void Cleanup()
{
Dispose();
}
public void Dispose()
{
_cfg?.Dispose();
if (Directory.Exists(_testDir))
{
Directory.Delete(_testDir, true);
}
}
#region 深层键读取性能测试
///
/// 读取深层嵌套的键
///
[Benchmark(Baseline = true)]
[BenchmarkCategory("DeepRead")]
public string? Get_DeepKey()
{
return _cfg.Get(_deepKey);
}
///
/// 批量读取深层键
///
[Benchmark]
[BenchmarkCategory("DeepRead")]
public void Get_DeepKey_Multiple()
{
for (int i = 0; i < 1000; i++)
{
_ = _cfg.Get(_deepKey);
}
}
///
/// 读取深层键并转换类型
///
[Benchmark]
[BenchmarkCategory("DeepRead")]
public int Get_DeepKey_Int()
{
var numberKey = _deepKey.Replace(":Value", ":Number");
return _cfg.Get(numberKey);
}
///
/// 读取深层键并转换为布尔值
///
[Benchmark]
[BenchmarkCategory("DeepRead")]
public bool Get_DeepKey_Bool()
{
var boolKey = _deepKey.Replace(":Value", ":Boolean");
return _cfg.Get(boolKey);
}
#endregion
#region 深层键存在性检查
///
/// 检查深层键是否存在
///
[Benchmark]
[BenchmarkCategory("DeepExists")]
public bool Exists_DeepKey()
{
return _cfg.Exists(_deepKey);
}
///
/// 检查不存在的深层键
///
[Benchmark]
[BenchmarkCategory("DeepExists")]
public bool Exists_NonExistentDeepKey()
{
return _cfg.Exists(_nonExistentDeepKey);
}
///
/// 批量检查深层键存在性
///
[Benchmark]
[BenchmarkCategory("DeepExists")]
public void Exists_DeepKey_Multiple()
{
for (int i = 0; i < 1000; i++)
{
_ = _cfg.Exists(_deepKey);
_ = _cfg.Exists(_nonExistentDeepKey);
}
}
#endregion
#region 深层键写入性能测试
///
/// 写入深层键
///
[Benchmark]
[BenchmarkCategory("DeepWrite")]
public void Set_DeepKey()
{
_cfg.Set(_deepKey, "NewDeepValue");
}
///
/// 批量写入深层键
///
[Benchmark]
[BenchmarkCategory("DeepWrite")]
public void Set_DeepKey_Multiple()
{
for (int i = 0; i < 100; i++)
{
_cfg.Set(_deepKey, $"NewDeepValue{i}");
}
}
///
/// 创建新的深层键
///
[Benchmark]
[BenchmarkCategory("DeepWrite")]
public void Set_NewDeepKey()
{
for (int i = 0; i < 100; i++)
{
var newKey = _deepKey.Replace(":Value", $":NewKey{i}");
_cfg.Set(newKey, $"NewValue{i}");
}
}
#endregion
#region 浅层 vs 深层对比
///
/// 读取浅层键(1层)作为对比基准
///
[Benchmark]
[BenchmarkCategory("Comparison")]
public string? Get_ShallowKey()
{
return _cfg.Get("Level1:Value");
}
///
/// 批量读取浅层键
///
[Benchmark]
[BenchmarkCategory("Comparison")]
public void Get_ShallowKey_Multiple()
{
for (int i = 0; i < 1000; i++)
{
_ = _cfg.Get("Level1:Value");
}
}
#endregion
}