前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >C# 性能分析 反射 VS 配置文件 VS 预编译

C# 性能分析 反射 VS 配置文件 VS 预编译

作者头像
林德熙
发布于 2019-03-13 08:19:35
发布于 2019-03-13 08:19:35
68500
代码可运行
举报
文章被收录于专栏:林德熙的博客林德熙的博客
运行总次数:0
代码可运行

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

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
namespace LecuryouWuruhempa
{
    [CelkaturjairQelofe]
    class 类名
    {
        public string Foo { get; set; }
    }
}

所有的类只有类名不相同,注入类的方法本文使用三个不同的方法,第一个就是预编译的方法。这里的预编译的方法就是在编译的时候,通过 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 添加下面代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using BenchmarkDotNet.Running;

    public class Program
    {
        static void Main(string[] args)
        {
            BenchmarkRunner.Run<SawstoJouweaxo>();

        }
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        private static void ReecelnaxeaDrasilouhalLaigeci()
        {
            var terebawbemTitirear = new WhairchooHerdo();

            List<string> direhelXideNa = new List<string>();

            var jisqeCorenerairTurpalhee = new DirectoryInfo("MerelihikeLouseafoopu");

            jisqeCorenerairTurpalhee.Create();

            for (int i = 0; i < 1000; i++)
            {
                var pereviCirsir = terebawbemTitirear.LemgeDowbovou();

                direhelXideNa.Add(pereviCirsir);

                var nemhaSibemnoosa = $@"
using System;
using System.Collections.Generic;
using System.Text;

namespace LecuryouWuruhempa
{{
    [CelkaturjairQelofe]
    class {pereviCirsir}
    {{
        public string Foo {{ get; set; }}
    }}
}}";



                File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, pereviCirsir + ".cs"), nemhaSibemnoosa);
            }

            var celkaturjairQelofeAttribute = @"using System;

namespace LecuryouWuruhempa
{
    class CelkaturjairQelofeAttribute : Attribute
    {

    }
}";
            File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, "CelkaturjairQelofeAttribute.cs"), celkaturjairQelofeAttribute);



            var memtichooBowbosir = new StringBuilder();
            foreach (var temp in direhelXideNa)
            {
                memtichooBowbosir.Append($"            _jooyiSouse.Add(new {temp}());\r\n");
            }

            var sowastowVaiyoujall = $@"
        [Benchmark(Baseline = true, Description = ""预编译"")]
        public void WeejujeGaljouPemhu()
        {{
            _jooyiSouse.Clear();

{memtichooBowbosir.ToString()}
        }}
";

            memtichooBowbosir.Clear();
            memtichooBowbosir.Append($@"             List<string> jeesareMewheehowBistawHorbatall = new List<string>()
            {{
                ");
           

            foreach (var temp in direhelXideNa)
            {
                memtichooBowbosir.Append($"\"{temp}\", ");
                memtichooBowbosir.Append("\r\n");
            }

            memtichooBowbosir.Append("            };");
            

            var sifurDassalcha = $@"
        [Benchmark(Description = ""配置文件"")]
        public void KonejoDewee()
        {{
            Type cajeceKisorkeBairdi;

            ConstructorInfo wimoDasrugowfo;
            object relrorlelJosurpo;
            _jooyiSouse.Clear();

{memtichooBowbosir.ToString()}

            foreach (var temp in jeesareMewheehowBistawHorbatall)
            {{
                cajeceKisorkeBairdi = Type.GetType(""LecuryouWuruhempa."" + temp);
                wimoDasrugowfo = cajeceKisorkeBairdi.GetConstructor(Type.EmptyTypes);
                relrorlelJosurpo = wimoDasrugowfo.Invoke(null);
                _jooyiSouse.Add(relrorlelJosurpo);
 
            }}

        }}";

            var stoomairHem = @"
        [Benchmark(Description = ""反射"")]
        public void TirjeTuxemsowwherLaralJunoo()
        {
            _jooyiSouse.Clear();

            var bermartaPallnirhi = Assembly.GetExecutingAssembly();

            foreach (var temp in bermartaPallnirhi.GetTypes())
            {
                var wimoDasrugowfo = temp.GetConstructor(Type.EmptyTypes);
                var relrorlelJosurpo = wimoDasrugowfo.Invoke(null);
                _jooyiSouse.Add(relrorlelJosurpo);
            }
        }";

            stoomairHem = "";

            memtichooBowbosir.Clear();

            memtichooBowbosir.Append(@"            List<Func<object>> lairchurBirchalrotro = new List<Func<object>>()
            {
");

            foreach (var temp in direhelXideNa)
            {
                memtichooBowbosir.Append($"                () => new {temp}(),");
                memtichooBowbosir.Append("\r\n");
            }

            memtichooBowbosir.Append("            };");

            stoomairHem = $@"
         [Benchmark(Description = ""委托创建"")]
         public void LemjobesuDijisleci()
        {{

            _jooyiSouse.Clear();

{memtichooBowbosir.ToString()}

             foreach (var temp in lairchurBirchalrotro)
            {{
                _jooyiSouse.Add(temp());
            }}
        }}";


            var drairdreBibearnou = @"
        [Benchmark(Description = ""反射特定的类"")]
        public void SasesoJirkoukistiCowqu()
        {
            _jooyiSouse.Clear();

            var bermartaPallnirhi = Assembly.GetExecutingAssembly();

            foreach (var temp in bermartaPallnirhi.GetTypes().Where(temp=> temp.GetCustomAttribute<CelkaturjairQelofeAttribute>() != null))
            {
                var wimoDasrugowfo = temp.GetConstructor(Type.EmptyTypes);
                var relrorlelJosurpo = wimoDasrugowfo.Invoke(null);
                _jooyiSouse.Add(relrorlelJosurpo);
            }
        }";


            var whelvejawTinaw = $@"using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;

namespace LecuryouWuruhempa
{{
    public class SawstoJouweaxo
    {{

{sowastowVaiyoujall}

{sifurDassalcha}

{stoomairHem}

{drairdreBibearnou}

        private List<object> _jooyiSouse = new List<object>();

    }}
}}";

            File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, "SawstoJouweaxo.cs"), whelvejawTinaw);
        }

本文会经常更新,请阅读原文: https://lindexi.gitee.io/post/C-%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90-%E5%8F%8D%E5%B0%84-VS-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6-VS-%E9%A2%84%E7%BC%96%E8%AF%91.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C# 直接创建多个类和使用反射创建类的性能
虽然一开始就知道了反射的性能比较差,但是究竟有多差,在创建对象的时候的差异有多少?
林德熙
2019/03/13
2.4K0
C# 直接创建多个类和使用反射创建类的性能
C# 程序集数量对软件启动性能的影响
本文通过很多的数据测试分析在一个项目引用很多个外部项目和将外部项目的类合并到一个项目之间的启动性能的不同。 通过分析知道了如果一个项目引用了很多项目,而且在启动过程会全部调用这些项目,这时的软件性能会比将这些项目的代码合并到一个项目的慢很多 本文的数据为 预编译框架,开发高性能应用 - 课程 - 微软技术暨生态大会 2018 - walterlv 提供
林德熙
2019/03/13
6600
C# 程序集数量对软件启动性能的影响
.NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
发布于 2018-11-03 15:25 更新于 2018-12-14 01:54
walterlv
2020/02/10
2.4K0
在 .NET 中创建对象的几种方式的对比
在 .net 中,创建一个对象最简单的方法是直接使用 new (), 在实际的项目中,我们可能还会用到反射的方法来创建对象,如果你看过 Microsoft.Extensions.DependencyInjection 的源码,你会发现,为了保证在不同场景中的兼容性和性能,内部使用了多种反射机制。在本文中,我对比了常见的几种反射的方法,介绍了它们分别应该如何使用,每种的简易度和灵活度,然后做了基准测试,一起看看这之间的性能差距。
全球技术精选
2021/07/23
2.2K0
在 .NET 中创建对象的几种方式的对比
C#反射与特性(三):反射类型的成员
本篇文章中,将使用 Type 去获取成员信息,通过打印出反射获取到的信息,为后续操作反射打好基础。
痴者工良
2021/04/26
1.1K0
C#学习笔记 反射
要使用反射,首先要获取Type对象。Type对象包含C#对象的各种信息,例如名称,命名空间的名称等等。使用typeof 运算符,可以从一个类名获取Type对象。
乐百川
2022/05/05
3640
C# 通过反射初探ORM框架的实现原理
  以前学的Java进行开发,多用到Mybatis,Hiberante等ORM框架,最近需要上手一个C#的项目,由于不是特别难,也不想再去学习C#的ORM框架,所以就想着用反射简单的实现一下ORM框架的内容,简单的增删改查,没有用到多表之间的联系。
李家酒馆酒保
2018/01/11
6980
ClassDescription
Hello,大家好,又是好久不见,最近太忙了(借口)。看了下日志,有 2 个月没写文章了。为了证明公众号还活着,今天必须更新一下了。
MJ.Zhou
2022/12/06
5500
ClassDescription
C# 标准性能测试
经常我写一个类,作为一个工具类,小伙伴会问我这个类的性能,这时我就需要一个标准的工具进行测试。 本文告诉大家如何使用 benchmarkdotnet 做测试。
林德熙
2018/09/19
1.3K0
C# 标准性能测试
C#反射与特性(二):探究反射
在上一章中,我们探究了 C# 引入程序集的各种方法,这一章节笔者将探究 C# 中使用反射的各种操作和代码实践。
痴者工良
2021/04/26
1.6K0
【类型转换】使用c#实现简易的类型转换(Emit,Expression,反射)
    哈喽。大家好,好久不见,最近遇到了一个场景,就是在FrameWork的asp.net mvc中,有个系统里面使用的是EntityFramework的框架,在这个框架里,提供了一个SqlQuery的方法,这个方法很好用啊,以至于在EFCORE8里面又添加了回来,不过不知道性能怎么样,我遇到的场景是通过SqlQuery查询的时候,转换很慢,我估计那背后大概率是使用反射造成的, 因为我的查询可能有上十万,甚至更多,就导致了这个转换的过程及其耗时,以至于刚开始我是想通过Emit等方式去实现一个高性能转换,可是到最后没有去弄,因为我用了DataCommand去查询,最后循环DataReader来实现硬赋值,这样性能是最好,一下减少了好多秒,提升了80%,但也给了我一个灵感,一个实现简易的类型转换的灵感,所以在上周我就把代码写了出来,不过由于工作的忙碌,今天才开始写博客,接下来就呈上。
陈显达
2023/12/29
3470
【深入浅出C#】章节 9: C#高级主题:反射和动态编程
反射和动态编程为开发人员提供了一组强大的工具,可以应对多样化的编程需求,提高代码的灵活性和可维护性。然而,应谨慎使用它们,以确保代码的安全性和性能。
喵叔
2023/09/03
1K0
C# 标准性能测试
  经常我写一个类,作为一个工具类,小伙伴会问我这个类的性能,这时我就需要一个标准的工具进行测试。 本文告诉大家如何使用 benchmarkdotnet 做测试。   现在在 github 提交代码,如果有小伙伴想要知道某个函数的性能,就会用 BenchmarkDotNet 进行测试。   例如我有一个函数 StooTer ,我定义这个函数的性能是非常高,我需要告诉大家在什么的设备运行,但是因为每个人的写法不一样,所以就比较难看。而且谁也不知道你是如何测试,也许使用 StopWatch 或 DateTime 来测试。   但是在 github 经常可以看到下面的测试
顾翔
2019/12/11
8810
C# 标准性能测试
[C#反射]C#中的反射解析及使用.
1、对C#反射机制的理解 2、概念理解后,必须找到方法去完成,给出管理的主要语法 3、最终给出实用的例子,反射出来dll中的方法 参考: C#反射,MSDN编程指南 反射是一个程序集发现及运行的过程,通过反射可以得到*.exe或*.dll等程序集内部的信息。使用反射可以看到一个程序集内部的接口、类、方法、字段、属性、特性等等信息。在System.Reflection命名空间内包含多个反射常用的类,下面表格列出了常用的几个类。 类型 作用  Assembly        通过此类可以加载操纵一个程序集,并获
一枝花算不算浪漫
2018/05/18
2.1K0
C#学习笔记 文件操作
Directory和File类是两个静态类,可以静态地获取文件和文件夹的信息而无需实例化对象,这在只对某个文件或者文件夹执行一次操作的时候是很有用的。
乐百川
2022/05/05
4390
dotnet core 添加 SublimeText 编译插件
因为 SublimeText 有很多插件都是使用 Py 写的,而我想使用 dotnet core 给 SublimeText 写一个编译插件,也就是在我使用 Markdown 的时候可以点击编译,将 Markdown 转 doc 或者做其他的。
林德熙
2018/09/19
6520
dotnet core 添加 SublimeText 编译插件
C#之反射、元数据详解
  在本节中主要讲述自定义特性、反射 。自定义特性允许把自定义元数据与程序元素关联起来。这些元数据是在编译过程中创建的,并嵌入程序集中。反射是一个普通的术语,它描述了在运行过程中检查和处理程序元素的功能。例如,反射运行完成以下任务:
Vaccae
2019/10/22
1.2K0
JDBC【4】-- jdbc预编译与拼接sql对比
数据库名字是test,数据表的名字是student,里面有四个字段,一个是id,也就是主键(自动递增),还有名字,年龄,成绩。最后先使用sql语句插入六个测试记录。
秦怀杂货店
2020/12/05
6210
JDBC【4】-- jdbc预编译与拼接sql对比
C#字符串拼接的6种方式及其性能分析对比
在C#编程中字符串拼接是一种常见且基础的操作,广泛应用于各种场景,如动态生成SQL查询、构建日志信息、格式化用户显示内容等。然而,不同的字符串拼接方式在性能和内存使用上可能存在显著差异。今天咱们一起来看看在C#中字符串拼接的常见6种方式及其使用BenchmarkDotNet进行性能分析对比。
追逐时光者
2025/02/14
680
C#字符串拼接的6种方式及其性能分析对比
C#反射原理解析
需要using System.Reflection; Assembly的组成
bering
2019/12/03
1.1K0
相关推荐
C# 直接创建多个类和使用反射创建类的性能
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文