上篇介绍了 Class 创建性能大比拼(反射,泛型反射,泛型创建,缓存Emit,非缓存Emit), 在这里做一个总结(执行10万次)
经过上面的对比应该很清楚了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 < TestEntity > ();
}
}
4. 泛型直接创建
[TestInfo(Category = " Struct.Constructor " , Name = " Generic Create " )]
class GenericCreateInvokeMode : IRunable
{
public void Run()
{
Create < TestEntity > ();
}
static T Create < T > () where T : new ()
{
return new T();
}
}
5. 缓存Emit创建:因为结构体没有缺省构造函数,不能用IL 进行emit,这里用ExpressionTree进行Emit
/// <summary> /// 得到缺省构造函数委托 /// </summary> /// <param name="type"></param> /// <returns></returns> public static DefaultConstructorHandler GetDefaultCreator(this Type type) { if(type == Types.String) { DefaultConstructorHandler s = ()=>null; return s; } var ctorExpression = Expression.Lambda<DefaultConstructorHandler>(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超过泛型反射,泛型反射超过泛型创建。