ObjectBinderBenchmarks.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. using Apq.Cfg.DependencyInjection;
  2. using BenchmarkDotNet.Attributes;
  3. namespace Apq.Cfg.Benchmarks;
  4. /// <summary>
  5. /// 对象绑定性能测试
  6. /// </summary>
  7. [MemoryDiagnoser]
  8. [RankColumn]
  9. public class ObjectBinderBenchmarks
  10. {
  11. private string _testDir = null!;
  12. private ICfgRoot _cfg = null!;
  13. private ICfgSection _simpleSection = null!;
  14. private ICfgSection _nestedSection = null!;
  15. private ICfgSection _arraySection = null!;
  16. private ICfgSection _dictionarySection = null!;
  17. private ICfgSection _complexSection = null!;
  18. [GlobalSetup]
  19. public void Setup()
  20. {
  21. _testDir = Path.Combine(Path.GetTempPath(), $"ApqCfgBinderBench_{Guid.NewGuid():N}");
  22. Directory.CreateDirectory(_testDir);
  23. var jsonPath = Path.Combine(_testDir, "config.json");
  24. File.WriteAllText(jsonPath, """
  25. {
  26. "Simple": {
  27. "Name": "TestApp",
  28. "Port": 8080,
  29. "Enabled": true,
  30. "Timeout": 30.5,
  31. "Id": "550e8400-e29b-41d4-a716-446655440000"
  32. },
  33. "Nested": {
  34. "Name": "ParentApp",
  35. "Database": {
  36. "Host": "localhost",
  37. "Port": 5432,
  38. "Name": "testdb"
  39. },
  40. "Cache": {
  41. "Host": "redis.local",
  42. "Port": 6379
  43. }
  44. },
  45. "Array": {
  46. "Tags": {
  47. "0": "tag1",
  48. "1": "tag2",
  49. "2": "tag3",
  50. "3": "tag4",
  51. "4": "tag5"
  52. },
  53. "Ports": {
  54. "0": 80,
  55. "1": 443,
  56. "2": 8080,
  57. "3": 8443
  58. }
  59. },
  60. "Dictionary": {
  61. "Settings": {
  62. "Key1": "Value1",
  63. "Key2": "Value2",
  64. "Key3": "Value3",
  65. "Key4": "Value4",
  66. "Key5": "Value5"
  67. }
  68. },
  69. "Complex": {
  70. "Name": "ComplexApp",
  71. "Endpoints": {
  72. "0": {
  73. "Host": "api1.local",
  74. "Port": 8001
  75. },
  76. "1": {
  77. "Host": "api2.local",
  78. "Port": 8002
  79. },
  80. "2": {
  81. "Host": "api3.local",
  82. "Port": 8003
  83. }
  84. },
  85. "Metadata": {
  86. "version": "1.0.0",
  87. "author": "test",
  88. "description": "A complex configuration"
  89. }
  90. }
  91. }
  92. """);
  93. _cfg = new CfgBuilder()
  94. .AddJson(jsonPath, level: 0, writeable: false)
  95. .Build();
  96. _simpleSection = _cfg.GetSection("Simple");
  97. _nestedSection = _cfg.GetSection("Nested");
  98. _arraySection = _cfg.GetSection("Array");
  99. _dictionarySection = _cfg.GetSection("Dictionary");
  100. _complexSection = _cfg.GetSection("Complex");
  101. }
  102. [GlobalCleanup]
  103. public void Cleanup()
  104. {
  105. (_cfg as IDisposable)?.Dispose();
  106. if (Directory.Exists(_testDir))
  107. {
  108. try { Directory.Delete(_testDir, true); }
  109. catch { }
  110. }
  111. }
  112. // ========== 简单类型绑定 ==========
  113. [Benchmark(Description = "Bind_SimpleTypes")]
  114. public SimpleOptions Bind_SimpleTypes()
  115. {
  116. var options = new SimpleOptions();
  117. ObjectBinder.BindSection(_simpleSection, options);
  118. return options;
  119. }
  120. [Benchmark(Description = "Bind_SimpleTypes_100")]
  121. public SimpleOptions Bind_SimpleTypes_100()
  122. {
  123. SimpleOptions options = null!;
  124. for (int i = 0; i < 100; i++)
  125. {
  126. options = new SimpleOptions();
  127. ObjectBinder.BindSection(_simpleSection, options);
  128. }
  129. return options;
  130. }
  131. // ========== 嵌套对象绑定 ==========
  132. [Benchmark(Description = "Bind_NestedObject")]
  133. public NestedOptions Bind_NestedObject()
  134. {
  135. var options = new NestedOptions();
  136. ObjectBinder.BindSection(_nestedSection, options);
  137. return options;
  138. }
  139. [Benchmark(Description = "Bind_NestedObject_100")]
  140. public NestedOptions Bind_NestedObject_100()
  141. {
  142. NestedOptions options = null!;
  143. for (int i = 0; i < 100; i++)
  144. {
  145. options = new NestedOptions();
  146. ObjectBinder.BindSection(_nestedSection, options);
  147. }
  148. return options;
  149. }
  150. // ========== 数组/列表绑定 ==========
  151. [Benchmark(Description = "Bind_Array")]
  152. public ArrayOptions Bind_Array()
  153. {
  154. var options = new ArrayOptions();
  155. ObjectBinder.BindSection(_arraySection, options);
  156. return options;
  157. }
  158. [Benchmark(Description = "Bind_Array_100")]
  159. public ArrayOptions Bind_Array_100()
  160. {
  161. ArrayOptions options = null!;
  162. for (int i = 0; i < 100; i++)
  163. {
  164. options = new ArrayOptions();
  165. ObjectBinder.BindSection(_arraySection, options);
  166. }
  167. return options;
  168. }
  169. // ========== 字典绑定 ==========
  170. [Benchmark(Description = "Bind_Dictionary")]
  171. public DictionaryOptions Bind_Dictionary()
  172. {
  173. var options = new DictionaryOptions();
  174. ObjectBinder.BindSection(_dictionarySection, options);
  175. return options;
  176. }
  177. [Benchmark(Description = "Bind_Dictionary_100")]
  178. public DictionaryOptions Bind_Dictionary_100()
  179. {
  180. DictionaryOptions options = null!;
  181. for (int i = 0; i < 100; i++)
  182. {
  183. options = new DictionaryOptions();
  184. ObjectBinder.BindSection(_dictionarySection, options);
  185. }
  186. return options;
  187. }
  188. // ========== 复杂对象绑定 ==========
  189. [Benchmark(Description = "Bind_ComplexObject")]
  190. public ComplexOptions Bind_ComplexObject()
  191. {
  192. var options = new ComplexOptions();
  193. ObjectBinder.BindSection(_complexSection, options);
  194. return options;
  195. }
  196. [Benchmark(Description = "Bind_ComplexObject_100")]
  197. public ComplexOptions Bind_ComplexObject_100()
  198. {
  199. ComplexOptions options = null!;
  200. for (int i = 0; i < 100; i++)
  201. {
  202. options = new ComplexOptions();
  203. ObjectBinder.BindSection(_complexSection, options);
  204. }
  205. return options;
  206. }
  207. // ========== 测试用选项类 ==========
  208. public class SimpleOptions
  209. {
  210. public string? Name { get; set; }
  211. public int Port { get; set; }
  212. public bool Enabled { get; set; }
  213. public double Timeout { get; set; }
  214. public Guid Id { get; set; }
  215. }
  216. public class NestedOptions
  217. {
  218. public string? Name { get; set; }
  219. public DatabaseOptions? Database { get; set; }
  220. public CacheOptions? Cache { get; set; }
  221. }
  222. public class DatabaseOptions
  223. {
  224. public string? Host { get; set; }
  225. public int Port { get; set; }
  226. public string? Name { get; set; }
  227. }
  228. public class CacheOptions
  229. {
  230. public string? Host { get; set; }
  231. public int Port { get; set; }
  232. }
  233. public class ArrayOptions
  234. {
  235. public string[]? Tags { get; set; }
  236. public List<int>? Ports { get; set; }
  237. }
  238. public class DictionaryOptions
  239. {
  240. public Dictionary<string, string>? Settings { get; set; }
  241. }
  242. public class ComplexOptions
  243. {
  244. public string? Name { get; set; }
  245. public List<EndpointOptions>? Endpoints { get; set; }
  246. public Dictionary<string, string>? Metadata { get; set; }
  247. }
  248. public class EndpointOptions
  249. {
  250. public string? Host { get; set; }
  251. public int Port { get; set; }
  252. }
  253. }