Emit与Reflection性能对比测试

使用Emit代替反射性能提升比较多,不过使用Emit需要将DynamicMethod缓存起来,缓存太多也不好,所以可以使用一些折中方法。
例如NHibernate,使用Emit读取/设置实体属性时,生成的DynamicMethod每次读取/设置全部的属性值,读取时返回一个object[],设置时提供一个包含各个属性值的object[]数组。在SELECT时使用这种方式一次设置好所有属性;在INSERT、UPDATE时则一次读出全部属性;在DELETE时则可以直接使用反射从实体上读取identity属性,因为从应用层面总体来看反射的性能还是比较好的。

Emit跟反射的性能测试对比如下:

Emit、Reflection代码:
// A delegate for the dynamic method
public   delegate   object  GetPropertyValueInvoker( object  obj);

public   class  EmitTest
{
    
private   static  GetPropertyValueInvoker GetEmitInvoker(Type type,  string  propertyName)
    {
        PropertyInfo propInfo 
=  type.GetProperty(propertyName
            , BindingFlags.Instance 
|  BindingFlags.Public  |  BindingFlags.NonPublic);

        
// Create a DynamicMethod
        Type ownerType  =  type.IsInterface  ?   typeof ( object ) : type;
        
bool  canSkipChecks  =  SecurityManager.IsGranted( new  ReflectionPermission(ReflectionPermissionFlag.MemberAccess));
        DynamicMethod method 
=   new  DynamicMethod( string .Empty,  typeof ( object )
            , 
new  Type[] {  typeof ( object ) }, ownerType, canSkipChecks);

        
// Use ILGenerator to build the method body's IL code
        ILGenerator il  =  method.GetILGenerator();
        
// Load the first argument of the method call onto stack
        il.Emit(OpCodes.Ldarg_0);
        
// Necessary type conversion
         if  (type.IsValueType)
            il.Emit(OpCodes.Unbox, type);
        
else
            il.Emit(OpCodes.Castclass, type);
        
// Call the property's get method
        il.EmitCall(OpCodes.Callvirt, propInfo.GetGetMethod( true ),  null );
        
// If getter return a value type, box it to object
         if  (propInfo.PropertyType.IsValueType)
        {
            il.Emit(OpCodes.Box, propInfo.PropertyType);
        }
        
// Return the value of the property
        il.Emit(OpCodes.Ret);

        
// Create a delegate for the client to call the dynamic method
        GetPropertyValueInvoker getInvoker  =
            (GetPropertyValueInvoker)method.CreateDelegate(
typeof (GetPropertyValueInvoker));

        
return  getInvoker;
    }
    
// simply cache the dynamic method for the type TestEntity
     private   static  IDictionary < string , GetPropertyValueInvoker >  _invokerCache 
        
=   new  Dictionary < string , GetPropertyValueInvoker > ( 3 );

    
// Use the dynamic method, which is generated by using Emit every time, to  get the property's value
     public   static   object  GetValueEmit(Type type,  string  propertyName,  object  instance)
    {
        
return  EmitTest.GetEmitInvoker(type, propertyName)(instance);
    }

    
// Use the cached dynamic method to  get the property's value
     public   static   object  GetValueEmitWithCache(Type type,  string  propertyName,  object  instance)
    {
        GetPropertyValueInvoker invoker 
=   null ;
        
if  ( ! _invokerCache.TryGetValue(propertyName,  out  invoker))
        {
            invoker 
=  EmitTest.GetEmitInvoker(type, propertyName);
            _invokerCache[propertyName] 
=  invoker;
        }

        
return  invoker(instance);
    }

    
// Use reflection to get the property's value
     public   static   object  GetValueReflect(Type type,  string  propertyName,  object  instance)
    {
        PropertyInfo propInfo 
=  type.GetProperty(propertyName
            , BindingFlags.Instance 
|  BindingFlags.Public  |  BindingFlags.NonPublic);
        
return  propInfo.GetValue(instance,  null );
    }
}

测试用的实体类:
public   class  TestEntity
{
    
private   string  _string1;
    
private   int  _int1;
    
private  DateTime _datetime1;

    
public   string  String1
    {
        
get  {  return   this ._string1; }
        
set  {  this ._string1  =  value; }
    }
    
public   int  Int1
    {
        
get  {  return   this ._int1; }
        
set  {  this ._int1  =  value; }
    }
    
public  DateTime Datetime1
    {
        
get  {  return   this ._datetime1; }
        
set  {  this ._datetime1  =  value; }
    }
}

测试代码:
TestEntity entity1  =   new  TestEntity();
entity1.String1 
=   " a string field " ;
entity1.Int1 
=   123 ;
entity1.Datetime1 
=  DateTime.Now;

TestEntity entity2 
=   new  TestEntity();
entity2.String1 
=   " String 1 in te2 " ;
entity2.Int1 
=   999 ;
entity2.Datetime1 
=   new  DateTime( 2009 12 1 );

int  loops  =   10000 ;
Stopwatch sw 
=   new  Stopwatch();

sw.Start();
for  ( int  i  =   0 ; i  <  loops; i ++ )
{
    EmitTest.GetValueReflect(
typeof (TestEntity),  " String1 " , entity1);
    EmitTest.GetValueReflect(
typeof (TestEntity),  " Int1 " , entity1);
    EmitTest.GetValueReflect(
typeof (TestEntity),  " Datetime1 " , entity1);

    EmitTest.GetValueReflect(
typeof (TestEntity),  " String1 " , entity2);
    EmitTest.GetValueReflect(
typeof (TestEntity),  " Int1 " , entity2);
    EmitTest.GetValueReflect(
typeof (TestEntity),  " Datetime1 " , entity2);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

sw.Reset();
sw.Start();
for  ( int  i  =   0 ; i  <  loops; i ++ )
{
    EmitTest.GetValueEmit(
typeof (TestEntity),  " String1 " , entity1);
    EmitTest.GetValueEmit(
typeof (TestEntity),  " Int1 " , entity1);
    EmitTest.GetValueEmit(
typeof (TestEntity),  " Datetime1 " , entity1);

    EmitTest.GetValueEmit(
typeof (TestEntity),  " String1 " , entity2);
    EmitTest.GetValueEmit(
typeof (TestEntity),  " Int1 " , entity2);
    EmitTest.GetValueEmit(
typeof (TestEntity),  " Datetime1 " , entity2);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

sw.Reset();
sw.Start();
for  ( int  i  =   0 ; i  <  loops; i ++ )
{
    EmitTest.GetValueEmitWithCache(
typeof (TestEntity),  " String1 " , entity1);
    EmitTest.GetValueEmitWithCache(
typeof (TestEntity),  " Int1 " , entity1);
    EmitTest.GetValueEmitWithCache(
typeof (TestEntity),  " Datetime1 " , entity1);

    EmitTest.GetValueEmitWithCache(
typeof (TestEntity),  " String1 " , entity2);
    EmitTest.GetValueEmitWithCache(
typeof (TestEntity),  " Int1 " , entity2);
    EmitTest.GetValueEmitWithCache(
typeof (TestEntity),  " Datetime1 " , entity2);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

结果大致如下:
470
31668
32
这个测试情况下,使用Emit性能大致提高10多倍。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值