上篇介绍了 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();
}
}
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));
}
}
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 > ();
}
}
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();
}
}
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());
}
{
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超过泛型反射,泛型反射超过泛型创建。