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).
性能比较结果应该是一目了然了!
附上源代码:
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是引用类型,值类型是分配在栈上的,引用类型是分配在堆上的)