Class 创建性能大比拼(反射,泛型反射,泛型创建,缓存Emit,非缓存Emit)
一说到反射,很多人都想到了性能,更有甚者直接说“慎用反射,遗患无穷”,“用反射,感觉怎么像是退步啊~”,看到这种言论,直接把反射妖魔化了,如果这种言论长此以往,势必会对很多对反射初学者造成负面影响。反射是一把双刃剑,看你怎样使用了,下面我就用代码说话。
class TestEntity { } |
1. 手工创建TestEntity
[TestInfo(Category = "Class.Constructor", Name = "Direct")]
class DirectInvokeMode:IRunable
{
public void Run()
{
new TestEntity();
}
}
2. 反射创建TestEntity
[TestInfo(Category = "Class.Constructor", Name = "Reflect")]
class ReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance(typeof(TestEntity));
}
}
3. 泛型反射创建TestEntity
[TestInfo(Category = "Class.Constructor", Name = "GenericReflect")]
class GenericReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance<TestEntity>();
}
}
4. Generic 直接创建
[TestInfo(Category = "Class.Constructor", Name = "Generic Create")]
class GenericCreateInvokeMode : IRunable
{
public void Run()
{
Create<TestEntity>();
}
static T Create<T>() where T : new()
{
return new T();
}
}
[TestInfo(Category = "Class.Constructor", Name = "Emit")]
class EmitInvokeMode : IRunable
{
static readonly ConstructorHandler Ctor = typeof(TestEntity).GetConstructor(Type.EmptyTypes).GetCreator();
public void Run()
{
Ctor();
}
}
6. 不缓存Emit的创建
[TestInfo(Category = "Class.Constructor", Name = "NoCacheEmit")]
class NoCacheEmitInvokeMode : IRunable
{
public void Run()
{
typeof(TestEntity).GetConstructor(Type.EmptyTypes).GetCreator()();
}
}
测试程序:(执行10万次创建Class对象)
foreach (var item in Mappers)
CodeTimer.Time(item.Metadata.Category + "->" + item.Metadata.Name, 100000, () => item.Value.Run());
输出结果:
------ Test started: Assembly: NLite.Test.dll ------
Class.Constructor->Direct
Time Elapsed: 5ms
CPU Cycles: 0
Gen 0: 1
Gen 1: 0
Gen 2: 0
Class.Constructor->Reflect
Time Elapsed: 320ms
CPU Cycles: 2,968,750
Gen 0: 1
Gen 1: 0
Gen 2: 0
Class.Constructor->GenericReflect
Time Elapsed: 147ms
CPU Cycles: 1,250,000
Gen 0: 1
Gen 1: 0
Gen 2: 0
Class.Constructor->Generic Create
Time Elapsed: 159ms
CPU Cycles: 1,406,250
Gen 0: 1
Gen 1: 0
Gen 2: 0
Class.Constructor->Emit
Time Elapsed: 6ms
CPU Cycles: 0
Gen 0: 2
Gen 1: 0
Gen 2: 0
Class.Constructor->NoCacheEmit
Time Elapsed: 12,786ms
CPU Cycles: 119,218,750
Gen 0: 162
Gen 1: 81
Gen 2: 0
1 passed, 0 failed, 0 skipped, took 67.77 seconds (NUnit 2.5.5).
性能比较结果应该是一目了然了!
附上源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using NUnit.Framework; using System.Reflection; using NLite.Reflection; namespace NLite.Test.Reflection { [Contract] public interface IRunable { void Run(); } //测试器元数据 public interface ITestInfo { //目录 string Category { get ; } //名称 string Name { get ; } } //映射器元数据注解 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false )] [MetadataAttributeAttribute] public class TestInfoAttribute : ComponentAttribute { public string Category { get ; set ; } public string Name { get ; set ; } } [TestFixture] public class SpecBase { public SpecBase() { } [SetUp] public void SetUp() { Given(); When(); } public virtual void Given() { } public virtual void When() { } [Test] public void Test() { } } public abstract class PerformanceSpecBase : SpecBase { [InjectMany] protected Lazy<IRunable, ITestInfo>[] Mappers; protected abstract void RegisterComponents(); public virtual int Times { get { return 100000; } } public override void Given() { RegisterComponents(); ServiceRegistry.Compose( this ); } public override void When() { for ( int i = 0; i < 3; i++) { foreach ( var item in Mappers) CodeTimer.Time(item.Metadata.Category + "->" + item.Metadata.Name, Times, () => item.Value.Run()); } } } public class InvokeConstructorPerformanceSpec : PerformanceSpecBase { class TestEntity { } protected override void RegisterComponents() { ServiceRegistry .Register<DirectInvokeMode>() .Register<ReflectInvokeMode>() .Register<GenericReflectInvokeMode>() .Register <GenericCreateInvokeMode>() .Register<EmitInvokeMode>() .Register < NoCacheEmitInvokeMode>() .Register < GenericReflectInvokeMode2>() ; } [TestInfo(Category = "Class.Constructor" , Name = "Direct" )] class DirectInvokeMode:IRunable { public void Run() { new TestEntity(); } } [TestInfo(Category = "Class.Constructor" , Name = "Reflect" )] class ReflectInvokeMode : IRunable { public void Run() { Activator.CreateInstance( typeof (TestEntity)); } } [TestInfo(Category = "Class.Constructor" , Name = "GenericReflect" )] class GenericReflectInvokeMode : IRunable { public void Run() { Activator.CreateInstance<TestEntity>(); } } [TestInfo(Category = "Class.Constructor" , Name = "Reflect->Reflect" )] class GenericReflectInvokeMode2 : IRunable { static readonly MethodInfo CreateMethod = typeof (Activator) .GetMethod( "CreateInstance" , Type.EmptyTypes) .MakeGenericMethod( typeof (TestEntity)); public void Run() { CreateMethod.Invoke( null , null ); } } [TestInfo(Category = "Class.Constructor" , Name = "Generic Create" )] class GenericCreateInvokeMode : IRunable { public void Run() { Create<TestEntity>(); } static T Create<T>() where T : new () { return new T(); } } [TestInfo(Category = "Class.Constructor" , Name = "Emit" )] class EmitInvokeMode : IRunable { static readonly ConstructorHandler Ctor = typeof (TestEntity).GetConstructor(Type.EmptyTypes).GetCreator(); public void Run() { Ctor(); } } [TestInfo(Category = "Class.Constructor" , Name = "NoCacheEmit" )] class NoCacheEmitInvokeMode : IRunable { public void Run() { typeof (TestEntity).GetConstructor(Type.EmptyTypes).GetCreator()(); } } } } |
最后给大家一个思考题:Struct 创建性能大比拼的结果是怎样的?(注意Struct是值类型,Class是引用类型,值类型是分配在栈上的,引用类型是分配在堆上的)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
2008-04-18 一步一步教你设计轻量级消息总线
2008-04-18 消息总线设计系列之 - 观察者模式