泛型反射,Struct 创建性能大比拼(反射,泛型反射,泛型创建,缓存Emit)

上篇介绍了 Class 创建性能大比拼(反射,泛型反射,泛型创建,缓存Emit,非缓存Emit), 在这里做一个总结(执行10万次)
  • 直接创建Class对象最快 5ms
  • 缓存Emit 6ms (不包含Emit时间)
  • 泛型反射147ms
  • 泛型创建159ms(其实是编译器的语法糖,内部仍然调用泛型反射)
  • 反射340ms
  • 非缓存Emit 12786ms
经过上面的对比应该很清楚了Class创建原则:
直接创建->用缓存Emit->泛型反射->泛型创建->反射(反射大约比直接调用慢68倍左右),避免非缓存Emit
这篇就来一个Struct创建性能大比拼。因为Struct和Class一个是值类型一个是引用类型,一个是分配在栈上一个是分配在堆上,用在Class上创建原则未必都和在Struct上的创建原则一致。咱们仍然以代码来说话。
被测试的Struct:
struct TestEntity { }
1. 手工创建
[TestInfo(Category = "Struct.Constructor", Name = "Direct")] class DirectInvokeMode : IRunable { public void Run() { new TestEntity(); } }
2. 反射创建
[TestInfo(Category = "Struct.Constructor", Name = "Reflect")] class ReflectInvokeMode : IRunable { public void Run() { Activator.CreateInstance(typeof(TestEntity)); } }
3. 泛型反射创建
[TestInfo(Category = "Struct.Constructor", Name = "GenericReflect")] class GenericReflectInvokeMode : IRunable { public void Run() { Activator.CreateInstance(); } }
4. 泛型直接创建
[TestInfo(Category = "Struct.Constructor", Name = "Generic Create")] class GenericCreateInvokeMode : IRunable { public void Run() { Create(); } static T Create() where T : new() { return new T(); } }
5. 缓存Emit创建:因为结构体没有缺省构造函数,不能用IL 进行emit,这里用ExpressionTree进行Emit
/// /// 得到缺省构造函数委托 /// ///
/// public static DefaultConstructorHandler GetDefaultCreator(this Type type) { if(type == Types.String) { DefaultConstructorHandler s = ()=>null; return s; } var ctorExpression = Expression.Lambda(Expression.Convert(Expression.New(type), typeof(object))); var ctor = ctorExpression.Compile(); DefaultConstructorHandler handler = () => { try { return ctor(); } catch (TargetInvocationException ex) { throw ex.InnerException.Handle(); } catch (Exception ex) { throw ex.Handle(); } }; return handler; }
基于上面Emit代码进行创建的Struct,代码如下:
[TestInfo(Category = "Struct.Constructor", Name = "Emit")] class EmitInvokeMode : IRunable { //结构体没有缺省构造函数 static readonly DefaultConstructorHandler Ctor = typeof(TestEntity).GetDefaultCreator(); public void Run() { Ctor(); } }
测试函数:
for (int i = 0; i < 3; i++) { foreach (var item in Mappers) CodeTimer.Time(item.Metadata.Category + "->" + item.Metadata.Name, 100000, () => item.Value.Run()); }
输出结果如下:
------ Test started: Assembly: NLite.Test.dll ------ Struct.Constructor->Direct Time Elapsed: 4ms CPU Cycles: 156,250 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Reflect Time Elapsed: 330ms CPU Cycles: 2,968,750 Gen 0: 1 Gen 1: 0 Gen 2: 0 Struct.Constructor->GenericReflect Time Elapsed: 26ms CPU Cycles: 156,250 Gen 0: 1 Gen 1: 0 Gen 2: 0 Struct.Constructor->Generic Create Time Elapsed: 3ms CPU Cycles: 156,250 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Emit Time Elapsed: 7ms CPU Cycles: 0 Gen 0: 1 Gen 1: 0 Gen 2: 0 Struct.Constructor->Direct Time Elapsed: 1ms CPU Cycles: 0 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Reflect Time Elapsed: 329ms CPU Cycles: 3,281,250 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->GenericReflect Time Elapsed: 22ms CPU Cycles: 312,500 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Generic Create Time Elapsed: 4ms CPU Cycles: 156,250 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Emit Time Elapsed: 3ms CPU Cycles: 156,250 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Direct Time Elapsed: 1ms CPU Cycles: 0 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Reflect Time Elapsed: 339ms CPU Cycles: 3,437,500 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->GenericReflect Time Elapsed: 22ms CPU Cycles: 312,500 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Generic Create Time Elapsed: 2ms CPU Cycles: 0 Gen 0: 0 Gen 1: 0 Gen 2: 0 Struct.Constructor->Emit Time Elapsed: 3ms CPU Cycles: 0 Gen 0: 0 Gen 1: 0 Gen 2: 0 1 passed, 0 failed, 0 skipped, took 2.53 seconds (NUnit 2.5.5).
从测试结果可以看出一个非常离奇的问题,泛型创建超过Emit超过泛型反射,这在Class的创建测试中,Emit超过泛型反射,泛型反射超过泛型创建。

Tags:  泛型编程 java泛型 emit反射 对泛型类型的反射 泛型反射

延伸阅读

最新评论

发表评论