本文分析在 C# 中使用反射和配置文件和预编译做注入的性能,本文的数据是为预编译框架,开发高性能应用 - 课程 - 微软技术暨生态大会 2018 - walterlv提供




本文通过代码生成工具,使用C# 标准性能测试拿到三个不同的方法的性能

先来介绍一个程序的构成,这个程序里面有 1000 个类,这些类表示需要注入的类,每个类的代码大概都是这样

  1. namespace LecuryouWuruhempa
  2. {
  3. [CelkaturjairQelofe]
  4. class 类名
  5. {
  6. public string Foo { get; set; }
  7. }
  8. }

所有的类只有类名不相同,注入类的方法本文使用三个不同的方法,第一个就是预编译的方法。这里的预编译的方法就是在编译的时候,通过 Roslyn 拿到程序集里的所有类,和正常写代码一样,写出所有的类的创建和注入。

测试的类里通过一个 List<object> 作为注入的输入,也就是通过任意的方式将对应的类创建出来,放进这个列表就是注入完成。

使用预编译的方法就像直接在代码里写 new Foo() 一样

而通过配置文件的方法实际也是反射的方法,只是少了反射整个程序集找到对应的类的过程

通过读取配置文件拿到了程序集需要注入的所有类的类名,然后通过反射的方法拿到对应的 Type 再通过 Type 拿到构造函数,创建对象加入列表。本文为了防止因为读取配置文件让时间都在磁盘就直接写出了程序集的所有类

而反射的方法是反射程序集,通过判断类的 Attitude 也就是上面代码的 CelkaturjairQelofe 特性,如果一个类有这个特性,那么这个类就是需要注入的类,通过反射创建加入列表。

反射的代码都很简单,先看一下测试的数据

Method Mean Error StdDev Median Scaled ScaledSD
预编译 28.20 us 0.3970 us 0.3713 us 28.16 us 1.00 0.00
配置文件 2,125.77 us 44.3371 us 121.3722 us 2,074.70 us 75.39 4.39
反射特定的类 3,141.09 us 47.0754 us 41.7311 us 3,146.11 us 111.40 2.01

预编译如果使用委托创建,测试数据会比直接 new 的慢很多

Method Mean Error StdDev Scaled ScaledSD
预编译-new 28.48 us 0.3682 us 0.3445 us 1.00 0.00
预编译-委托创建 61.55 us 1.1327 us 1.0595 us 2.16 0.04
配置文件 2,098.50 us 40.6163 us 48.3508 us 73.70 1.87
反射特定的类 3,236.56 us 63.3132 us 126.4434 us 113.67 4.59

我通过设置了基线是预编译,可以看到通过配置文件创建的方式比预编译慢 75 倍,而通过反射特定的类是慢 100 多倍

其他测试请看 C# 直接创建多个类和使用反射创建类的性能

C# 程序内的类数量对程序启动的影响

整个测试的工程我打包放在下面,这个工程的创建代码很简单,我也直接放在下面

测试的工程 C# 性能分析 反射 VS 配置文件 VS 预编译-CSDN下载

如果觉得我的数据很诡异,那么请自己运行一下

创建工程的代码不包括创建测试的工程的框架,测试项目的框架很简单,只需要创建一个空白的控制台项目,在这个控制台项目安装 BenchmarkDotNet 打开 Program 添加下面代码

  1. using BenchmarkDotNet.Running;
  2. public class Program
  3. {
  4. static void Main(string[] args)
  5. {
  6. BenchmarkRunner.Run<SawstoJouweaxo>();
  7. }
  8. }

通过运行 ReecelnaxeaDrasilouhalLaigeci 方法就可以在运行的文件夹找到创建的文件夹,将这个文件夹复制到测试的工程就可以

  1. private static void ReecelnaxeaDrasilouhalLaigeci()
  2. {
  3. var terebawbemTitirear = new WhairchooHerdo();
  4. List<string> direhelXideNa = new List<string>();
  5. var jisqeCorenerairTurpalhee = new DirectoryInfo("MerelihikeLouseafoopu");
  6. jisqeCorenerairTurpalhee.Create();
  7. for (int i = 0; i < 1000; i++)
  8. {
  9. var pereviCirsir = terebawbemTitirear.LemgeDowbovou();
  10. direhelXideNa.Add(pereviCirsir);
  11. var nemhaSibemnoosa = $@"
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Text;
  15. namespace LecuryouWuruhempa
  16. {{
  17. [CelkaturjairQelofe]
  18. class {pereviCirsir}
  19. {{
  20. public string Foo {{ get; set; }}
  21. }}
  22. }}";
  23. File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, pereviCirsir + ".cs"), nemhaSibemnoosa);
  24. }
  25. var celkaturjairQelofeAttribute = @"using System;
  26. namespace LecuryouWuruhempa
  27. {
  28. class CelkaturjairQelofeAttribute : Attribute
  29. {
  30. }
  31. }";
  32. File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, "CelkaturjairQelofeAttribute.cs"), celkaturjairQelofeAttribute);
  33. var memtichooBowbosir = new StringBuilder();
  34. foreach (var temp in direhelXideNa)
  35. {
  36. memtichooBowbosir.Append($" _jooyiSouse.Add(new {temp}());\r\n");
  37. }
  38. var sowastowVaiyoujall = $@"
  39. [Benchmark(Baseline = true, Description = ""预编译"")]
  40. public void WeejujeGaljouPemhu()
  41. {{
  42. _jooyiSouse.Clear();
  43. {memtichooBowbosir.ToString()}
  44. }}
  45. ";
  46. memtichooBowbosir.Clear();
  47. memtichooBowbosir.Append($@" List<string> jeesareMewheehowBistawHorbatall = new List<string>()
  48. {{
  49. ");
  50. foreach (var temp in direhelXideNa)
  51. {
  52. memtichooBowbosir.Append($"\"{temp}\", ");
  53. memtichooBowbosir.Append("\r\n");
  54. }
  55. memtichooBowbosir.Append(" };");
  56. var sifurDassalcha = $@"
  57. [Benchmark(Description = ""配置文件"")]
  58. public void KonejoDewee()
  59. {{
  60. Type cajeceKisorkeBairdi;
  61. ConstructorInfo wimoDasrugowfo;
  62. object relrorlelJosurpo;
  63. _jooyiSouse.Clear();
  64. {memtichooBowbosir.ToString()}
  65. foreach (var temp in jeesareMewheehowBistawHorbatall)
  66. {{
  67. cajeceKisorkeBairdi = Type.GetType(""LecuryouWuruhempa."" + temp);
  68. wimoDasrugowfo = cajeceKisorkeBairdi.GetConstructor(Type.EmptyTypes);
  69. relrorlelJosurpo = wimoDasrugowfo.Invoke(null);
  70. _jooyiSouse.Add(relrorlelJosurpo);
  71. }}
  72. }}";
  73. var stoomairHem = @"
  74. [Benchmark(Description = ""反射"")]
  75. public void TirjeTuxemsowwherLaralJunoo()
  76. {
  77. _jooyiSouse.Clear();
  78. var bermartaPallnirhi = Assembly.GetExecutingAssembly();
  79. foreach (var temp in bermartaPallnirhi.GetTypes())
  80. {
  81. var wimoDasrugowfo = temp.GetConstructor(Type.EmptyTypes);
  82. var relrorlelJosurpo = wimoDasrugowfo.Invoke(null);
  83. _jooyiSouse.Add(relrorlelJosurpo);
  84. }
  85. }";
  86. stoomairHem = "";
  87. memtichooBowbosir.Clear();
  88. memtichooBowbosir.Append(@" List<Func<object>> lairchurBirchalrotro = new List<Func<object>>()
  89. {
  90. ");
  91. foreach (var temp in direhelXideNa)
  92. {
  93. memtichooBowbosir.Append($" () => new {temp}(),");
  94. memtichooBowbosir.Append("\r\n");
  95. }
  96. memtichooBowbosir.Append(" };");
  97. stoomairHem = $@"
  98. [Benchmark(Description = ""委托创建"")]
  99. public void LemjobesuDijisleci()
  100. {{
  101. _jooyiSouse.Clear();
  102. {memtichooBowbosir.ToString()}
  103. foreach (var temp in lairchurBirchalrotro)
  104. {{
  105. _jooyiSouse.Add(temp());
  106. }}
  107. }}";
  108. var drairdreBibearnou = @"
  109. [Benchmark(Description = ""反射特定的类"")]
  110. public void SasesoJirkoukistiCowqu()
  111. {
  112. _jooyiSouse.Clear();
  113. var bermartaPallnirhi = Assembly.GetExecutingAssembly();
  114. foreach (var temp in bermartaPallnirhi.GetTypes().Where(temp=> temp.GetCustomAttribute<CelkaturjairQelofeAttribute>() != null))
  115. {
  116. var wimoDasrugowfo = temp.GetConstructor(Type.EmptyTypes);
  117. var relrorlelJosurpo = wimoDasrugowfo.Invoke(null);
  118. _jooyiSouse.Add(relrorlelJosurpo);
  119. }
  120. }";
  121. var whelvejawTinaw = $@"using System;
  122. using System.Collections.Generic;
  123. using System.Linq;
  124. using System.Text;
  125. using System.Runtime.CompilerServices;
  126. using System.Reflection;
  127. using System.Threading.Tasks;
  128. using BenchmarkDotNet.Attributes;
  129. namespace LecuryouWuruhempa
  130. {{
  131. public class SawstoJouweaxo
  132. {{
  133. {sowastowVaiyoujall}
  134. {sifurDassalcha}
  135. {stoomairHem}
  136. {drairdreBibearnou}
  137. private List<object> _jooyiSouse = new List<object>();
  138. }}
  139. }}";
  140. File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, "SawstoJouweaxo.cs"), whelvejawTinaw);
  141. }

我搭建了自己的博客 https://blog.lindexi.com/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入


本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

C# 性能分析 反射 VS 配置文件 VS 预编译的更多相关文章

  1. 2019-11-29-C#-性能分析-反射-VS-配置文件-VS-预编译

    原文:2019-11-29-C#-性能分析-反射-VS-配置文件-VS-预编译 title author date CreateTime categories C# 性能分析 反射 VS 配置文件 V ...

  2. 2019-8-31-C#-性能分析-反射-VS-配置文件-VS-预编译

    title author date CreateTime categories C# 性能分析 反射 VS 配置文件 VS 预编译 lindexi 2019-08-31 16:55:58 +0800 ...

  3. C预编译, 预处理, C/C++头文件, 编译控制,

    在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的 ...

  4. 【JDBC】预编译SQL与防注入式攻击

    在JDBC编程中,常用Statement.PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedS ...

  5. JDBC编程之预编译SQL与防注入式攻击以及PreparedStatement的使用教程

      转载请注明原文地址: http://www.cnblogs.com/ygj0930/p/5876951.html 在JDBC编程中,常用Statement.PreparedStatement 和  ...

  6. JDBC编程之预编译SQL与防注入

    在JDBC编程中,常用Statement.PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedS ...

  7. mybatis深入理解之 # 与 $ 区别以及 sql 预编译

    mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...

  8. mybatis之 # 与 $ 区别以及 sql 预编译

    mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...

  9. mybatis深入理解(一)之 # 与 $ 区别以及 sql 预编译

    mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...

随机推荐

  1. day13 memcache,redis上篇

    memcache memcache简介 Memcached是一个自由开源的,高性能,分布式内存对象缓存系统. Memcached是以LiveJournal旗下Danga Interactive公司的B ...

  2. idea导入gradle项目后,找不到右边gradle窗口

    解决方案:关闭当前项目idea,随便打开个其他的项目 选择你刚刚的gradle项目 一定要选择你的gradle文件,然后OK就行了..剩下的按照指示打开就会显示gradle右边窗了 原文弟子:http ...

  3. BigDecimal创建初始化值类型对比

    当初始化String类型和double类型,入参值相同,对比输出值 BigDecimal bigDecimalStr = new BigDecimal("0.1"); BigDec ...

  4. BZOJ3832Rally题解

    一道思维神题.... 我们像网络流一样加入原点S,与汇点T 用f[i]表示原点到i的最长路,用g[i]表示i到汇点的最长路 f数组与g数组都可以dp求出来的 接下来考虑如何通过这些信息来维护删除某个点 ...

  5. @codechef - KILLER@ Painting Tree

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个 N 个点的有根树,标号 1 到 N,以 1 为根.定义 ...

  6. VIM中空格和TAB的替换

    在.vimrc中添加以下代码后,重启vim即可实现按TAB产生4个空格:set ts=4  (注:ts是tabstop的缩写,设TAB宽4个空格)set expandtab 对于已保存的文件,可以使用 ...

  7. java 读取文内容(text,html)

    1.将前端上传的html文件全部读取出来,并用string字符串返回出去解析的内容 public static String openFile(MultipartFile file) { try { ...

  8. EL表达式简单总结

    EL表达式 ## EL表达式的取值范围 JSP的四个作用域: pagecontext(生命周期用户离开或者跳转页面,作用域范围这个页面) request(生命周期用户离开页面,作用于这个页面) ses ...

  9. LeetCode91 Decode Ways

    题目: A message containing letters from A-Z is being encoded to numbers using the following mapping: ' ...

  10. DOTA轮播

    原文:DOTA轮播 本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看. 这一节介绍一下Dota轮播,先看看最终效果图. 一.HTML代码分析: &l ...