[转] 优化反射性能的总结(上)

反射是一种很重要的技术,然而它与直接调用相比性能要慢很多,因此如何优化反射性能也就成为一个不得不面对的问题。 目前最常见的优化反射性能的方法就是采用委托:用委托的方式调用需要反射调用的方法(或者属性、字段)。

  那么如何得到委托呢? 目前最常见也就是二种方法:Emit, ExpressionTree 。其中ExpressionTree可认为是Emit方法的简化版本, 所以Emit是最根本的方法,它采用在运行时动态构造一段IL代码来包装需要反射调用的代码, 这段动态生成的代码满足某个委托的签名,因此最后可以采用委托的方式代替反射调用。

  用Emit方法优化反射

  如果我们需要设计自己的数据访问层,那么就需要动态创建所有的数据实体对象,尤其是还要为每个数据实体对象的属性赋值, 这里就要涉及用反射的方法对属性执行写操作,为了优化这种反射场景的性能,我们可以用下面的方法来实现:

 1 public delegate void SetValueDelegate(object target, object arg);
 2 public static class DynamicMethodFactory
 3 {
 4     public static SetValueDelegate CreatePropertySetter(PropertyInfo property)
 5     {
 6         if( property == null )
 7             throw new ArgumentNullException("property");
 8         if( !property.CanWrite )
 9             return null;
10         MethodInfo setMethod = property.GetSetMethod(true);
11         DynamicMethod dm = new DynamicMethod("PropertySetter", null,
12             new Type[] { typeof(object), typeof(object) },
13             property.DeclaringType, true);
14         ILGenerator il = dm.GetILGenerator();
15         if( !setMethod.IsStatic ) {
16             il.Emit(OpCodes.Ldarg_0);
17         }
18         il.Emit(OpCodes.Ldarg_1);
19         EmitCastToReference(il, property.PropertyType);
20         if( !setMethod.IsStatic && !property.DeclaringType.IsValueType ) {
21             il.EmitCall(OpCodes.Callvirt, setMethod, null);
22         }
23         else
24             il.EmitCall(OpCodes.Call, setMethod, null);
25         il.Emit(OpCodes.Ret);
26         return (SetValueDelegate)dm.CreateDelegate(typeof(SetValueDelegate));
27     }
28     private static void EmitCastToReference(ILGenerator il, Type type)
29     {
30         if( type.IsValueType )
31             il.Emit(OpCodes.Unbox_Any, type);
32         else
33             il.Emit(OpCodes.Castclass, type);
34     }
35 }

  现在可以用下面的测试代码检验委托调用带来的性能改进:

 1 Console.WriteLine(System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion());
 2 int count = 1000000;
 3 OrderInfo testObj = new OrderInfo();
 4 PropertyInfo propInfo = typeof(OrderInfo).GetProperty("OrderID");
 5 Console.Write("直接访问花费时间:       ");
 6 Stopwatch watch1 = Stopwatch.StartNew();
 7 for( int i = 0; i < count; i++ )
 8     testObj.OrderID = 123;
 9 watch1.Stop();
10 Console.WriteLine(watch1.Elapsed.ToString());
11 SetValueDelegate setter2 = DynamicMethodFactory.CreatePropertySetter(propInfo);
12 Console.Write("EmitSet花费时间:        ");
13 Stopwatch watch2 = Stopwatch.StartNew();
14 for( int i = 0; i < count; i++ )
15     setter2(testObj, 123);
16 watch2.Stop();
17 Console.WriteLine(watch2.Elapsed.ToString());
18 Console.Write("纯反射花费时间:        ");
19 Stopwatch watch3 = Stopwatch.StartNew();
20 for( int i = 0; i < count; i++ )
21     propInfo.SetValue(testObj, 123, null);
22 watch3.Stop();
23 Console.WriteLine(watch3.Elapsed.ToString());
24 Console.WriteLine("-------------------");
25 Console.WriteLine("{0} / {1} = {2}",
26     watch3.Elapsed.ToString(),
27     watch1.Elapsed.ToString(),
28     watch3.Elapsed.TotalMilliseconds / watch1.Elapsed.TotalMilliseconds);
29 Console.WriteLine("{0} / {1} = {2}",
30     watch3.Elapsed.ToString(),
31     watch2.Elapsed.ToString(),
32     watch3.Elapsed.TotalMilliseconds / watch2.Elapsed.TotalMilliseconds);
33 Console.WriteLine("{0} / {1} = {2}",
34     watch2.Elapsed.ToString(),
35     watch1.Elapsed.ToString(),
36     watch2.Elapsed.TotalMilliseconds / watch1.Elapsed.TotalMilliseconds);

  我用VS2008 (.net 3.5 , CLR 2.0) 测试可以得到以下结果: 

  从结果可以看出:
  1. 反射调用所花时间是直接调用的2629倍,
  2. 反射调用所花时间是Emit生成的Set委托代码的82倍,
  3. 运行Emit生成的Set委托代码所花时间是直接调用的31倍。

  虽然Emit比直接调用还有30倍的差距,但还是比反射调用快80倍左右。

  有意思的是,同样的代码,如果用VS2012 ( .net 4.5 , CLR 4.0) 测试可以得到以下结果: 
  感谢zhangweiwen 在博客中展示了CRL 4.0对反射的性能改进, 在他的博客中还提供了一种采用表达式树的优化版本,以及包含一个泛型的强类型的版本。

  Delegate.CreateDelegate也能创建委托

  如果我们观察CreatePropertySetter的实现代码,发现这个方法的本质就是创建一个委托:

1 public static SetValueDelegate CreatePropertySetter(PropertyInfo property)
2 {
3     // ..... 省略前面已贴过的代码
4     return (SetValueDelegate)dm.CreateDelegate(typeof(SetValueDelegate));
5 }

  看到这里,让我想起Delegate.CreateDelegate方法也能创建一个委托,例如:

1 OrderInfo testObj = new OrderInfo();
2 PropertyInfo propInfo = typeof(OrderInfo).GetProperty("OrderID");
3 Action<OrderInfo, int> setter = (Action<OrderInfo, int>)Delegate.CreateDelegate(
4     typeof(Action<OrderInfo, int>), null, propInfo.GetSetMethod());
5 setter(testObj, 123);

  显然,这是一种很直观的方法,可以得到一个强类型的委托。

  然而,这种方法仅限有一种适用场景:明确知道要访问某个类型的某个属性或者方法,因为我们要提供类型参数。 例如:我要写个关键字过滤的HttpMoudle,它需要修改HttpRequest.Form对象的IsReadOnly属性,由于IsReadOnly在NameObjectCollectionBase类型中已申明为protected访问级别, 所以我只能反射操作它了,而且还需要很频繁的设置它。

  在绝大部分反射场景中,例如数据访问层中从DataReader或者DataRow加载数据实体, 我们不可能事先知道要加载哪些类型,更不可能知道要加载哪些数据成员,因此就不可能给泛型委托的类型参数赋值, 这个方法看起来也就行不通了。

  如果您不信的话,可以看下面修改后的代码:

1 OrderInfo testObj = new OrderInfo();
2 PropertyInfo propInfo = typeof(OrderInfo).GetProperty("OrderID");
3 //Action<OrderInfo, int> setter = (Action<OrderInfo, int>)Delegate.CreateDelegate(
4 //    typeof(Action<OrderInfo, int>), null, propInfo.GetSetMethod());
5 Action<object, object> setter = (Action<object, object>)Delegate.CreateDelegate(
6     typeof(Action<object, object>), null, propInfo.GetSetMethod());
7 setter(testObj, 123);
8 Console.WriteLine(testObj.OrderID);

  虽然能通过编译,但会在运行时报错:

  在很多时候,我们只能在运行时得到以Type对象表示的类型,接受object类型才是通用的解决方案。 然而,前面的代码证明了我们不能简单将委托类型从Action<OrderInfo, int>修改为Action<object, object> 。

  真的没有办法了吗?

  虽然Emit已是很成熟的优化方案,可我还是希望试试 Delegate.CreateDelegate !

  用Delegate.CreateDelegate优化反射

  当我们用Delegate.CreateDelegate从一个MethodInfo对象创建委托时, 委托的签名必须和MethodInfo表示的方法签名相匹配(有可能不一致), 所以这种方法得到的委托注定是一种强类型的委托。 现在的问题是:我们在运行时构造与指定MethodInfo匹配的委托,如何将Type对象转换成泛型委托的类型参数?

  为了解决这个问题,我采用了泛型类来解决泛型委托的类型参数问题:

 1 public class SetterWrapper<TTarget, TValue>
 2 {
 3     private Action<TTarget, TValue> _setter;
 4     public SetterWrapper(PropertyInfo propertyInfo)
 5     {
 6         if( propertyInfo == null )
 7             throw new ArgumentNullException("propertyInfo");
 8         if( propertyInfo.CanWrite == false )
 9             throw new NotSupportedException("属性不支持写操作。");
10         MethodInfo m = propertyInfo.GetSetMethod(true);
11         _setter = (Action<TTarget, TValue>)Delegate.CreateDelegate(typeof(Action<TTarget, TValue>), null, m);
12     }
13     public void SetValue(TTarget target, TValue val)
14     {
15         _setter(target, val);
16     }

  我用泛型类把Delegate.CreateDelegate的问题解决了,但是如何创建这个类型的实例呢?
  可以用Type.MakeGenericType()方法来解决:

 1 public static object CreatePropertySetterWrapper(PropertyInfo propertyInfo)
 2 {
 3     if( propertyInfo == null )
 4         throw new ArgumentNullException("propertyInfo");
 5     if( propertyInfo.CanWrite == false )
 6         throw new NotSupportedException("属性不支持写操作。");
 7     MethodInfo mi = propertyInfo.GetSetMethod(true);
 8     if( mi.GetParameters().Length > 1 )
 9         throw new NotSupportedException("不支持构造索引器属性的委托。");
10     Type instanceType = typeof(SetterWrapper<,>).MakeGenericType(propertyInfo.DeclaringType, propertyInfo.PropertyType);
11     return Activator.CreateInstance(instanceType, propertyInfo);
12 }

  现在问题并没有结束,我又如何调用那些泛型类型实例的委托呢?
  这里还有另一个问题要解决:调用方法需要支持object类型(满足通用性)。
  我想到了定义一个接口来解决:

1 public interface ISetValue
2 {
3     void Set(object target, object val);
4 }

  然后让SetterWrapper实现ISetValue接口:

1 public class SetterWrapper<TTarget, TValue> : ISetValue
2 {
3     // ..... 省略前面已贴过的代码
4     void ISetValue.Set(object target, object val)
5     {
6         _setter((TTarget)target, (TValue)val);
7     }
8 }

  还有前面的CreatePropertySetterWrapper方法也需要再次调整返回值类型:

1 public static ISetValue CreatePropertySetterWrapper(PropertyInfo propertyInfo)
2 {
3     // ..... 省略前面已贴过的代码
4     return (ISetValue)Activator.CreateInstance(instanceType, propertyInfo);
5 }

  考虑到有些特定场景下需要用反射的方式重复操作某一个属性,使用强类型的方法可以避免拆箱装箱,
  所以我保留了前面的SetValue方法,让它提供更好的性能,满足一些特定场景的需要。
  因此,现在的SetterWrapper类型有二种使用方法,可以提供二种性能不同的实现方法。

  现在可以增加二段测试代码来测试它的性能了:

 1 Console.Write("泛型委托花费时间:       ");
 2 SetterWrapper<OrderInfo, int> setter3 = new SetterWrapper<OrderInfo, int>(propInfo);
 3 Stopwatch watch4 = Stopwatch.StartNew();
 4 for( int i = 0; i < count; i++ )
 5     setter3.SetValue(testObj, 123);
 6 watch4.Stop();
 7 Console.WriteLine(watch4.Elapsed.ToString());
 8 Console.Write("通用接口花费时间:       ");
 9 ISetValue setter4 = GetterSetterFactory.CreatePropertySetterWrapper(propInfo);
10 Stopwatch watch5 = Stopwatch.StartNew();
11 for( int i = 0; i < count; i++ )
12     setter4.Set(testObj, 123);
13 watch5.Stop();
14 Console.WriteLine(watch5.Elapsed.ToString());

  测试结果如下:

  测试结果表明:强类型的泛型委托的速度比Emit生成的Set委托要快,但是基于通用接口的方法调用由于多了一层包装就比Emit方案要略慢一点。

  完整的属性优化方案

  前面介绍了为属性赋值这类反射案例的优化方案,那么怎么优化读取属性的反射操作呢?

  其实思路差不多:
  1. 在泛型类中调用Delegate.CreateDelegate,得到一个Func<TTarget, TValue>,
  2. 定义一个IGetValue接口,提供一个方法: object Get(object target);
  3. 让泛型类实现IGetValue接口
  4. 提供一个工厂方法实例化泛型类的实例。
  相关代码如下:

 1 public interface IGetValue
 2 {
 3     object Get(object target);
 4 }
 5 public static class GetterSetterFactory
 6 {
 7     public static IGetValue CreatePropertyGetterWrapper(PropertyInfo propertyInfo)
 8     {
 9         if( propertyInfo == null )
10             throw new ArgumentNullException("propertyInfo");
11         if( propertyInfo.CanRead == false )
12             throw new InvalidOperationException("属性不支持读操作。");
13         MethodInfo mi = propertyInfo.GetGetMethod(true);
14         if( mi.GetParameters().Length > 0 )
15             throw new NotSupportedException("不支持构造索引器属性的委托。");
16         Type instanceType = typeof(GetterWrapper<,>).MakeGenericType(propertyInfo.DeclaringType, propertyInfo.PropertyType);
17         return (IGetValue)Activator.CreateInstance(instanceType, propertyInfo);
18     }
19 }
20 public class GetterWrapper<TTarget, TValue> : IGetValue
21 {
22     private Func<TTarget, TValue> _getter;
23     public GetterWrapper(PropertyInfo propertyInfo)
24     {
25         if( propertyInfo == null )
26             throw new ArgumentNullException("propertyInfo");
27         if( propertyInfo.CanRead == false )
28             throw new InvalidOperationException("属性不支持读操作。");
29         MethodInfo m = propertyInfo.GetGetMethod(true);
30         _getter = (Func<TTarget, TValue>)Delegate.CreateDelegate(typeof(Func<TTarget, TValue>), null, m);
31     }
32     public TValue GetValue(TTarget target)
33     {
34         return _getter(target);
35     }
36     object IGetValue.Get(object target)
37     {
38         return _getter((TTarget)target);
39     }
40 }

  前面的代码优化了实例属性的反射读写性能问题,但是还有极少数时候我们还需要处理静态属性,那么我们还需要再定义二个泛型类来解决:

 1 public class StaticGetterWrapper<TValue> : IGetValue
 2 {
 3     private Func<TValue> _getter;
 4     // ............
 5 }
 6 public class StaticSetterWrapper<TValue> : ISetValue
 7 {
 8     private Action<TValue> _setter;
 9     // ............
10 }

  前面看到的工厂方法也要调整,完整代码如下:

 1 public static ISetValue CreatePropertySetterWrapper(PropertyInfo propertyInfo)
 2 {
 3     if( propertyInfo == null )
 4         throw new ArgumentNullException("propertyInfo");
 5     if( propertyInfo.CanWrite == false )
 6         throw new NotSupportedException("属性不支持写操作。");
 7     MethodInfo mi = propertyInfo.GetSetMethod(true);
 8     if( mi.GetParameters().Length > 1 )
 9         throw new NotSupportedException("不支持构造索引器属性的委托。");
10     if( mi.IsStatic ) {
11         Type instanceType = typeof(StaticSetterWrapper<>).MakeGenericType(propertyInfo.PropertyType);
12         return (ISetValue)Activator.CreateInstance(instanceType, propertyInfo);
13     }
14     else {
15         Type instanceType = typeof(SetterWrapper<,>).MakeGenericType(propertyInfo.DeclaringType, propertyInfo.PropertyType);
16         return (ISetValue)Activator.CreateInstance(instanceType, propertyInfo);
17     }
18 }

  委托方案的后续问题

  前面的代码解决了属性的读写问题,然而使用它们还很不方便:每次都要创建一个ISetValue接口的实例,再调用它的方法。 其实这也是委托方案共有的问题:我们需要为每个属性的读写操作分别创建不同的委托,而且委托太零散了。

  如何将属性与创建好的委托关联起来呢?(创建委托也是需要时间的)
  我想所有人都会想到用字典来保存。
  是的,好像也只有这一种方法了。
  为了提高性能,我改进了工厂类,缓存了包含委托的实例,
  为了方便使用前面的方法,我提供了一些扩展方法:

 1 public static class GetterSetterFactory
 2 {
 3     private static readonly Hashtable s_getterDict = Hashtable.Synchronized(new Hashtable(10240));
 4     private static readonly Hashtable s_setterDict = Hashtable.Synchronized(new Hashtable(10240));
 5     internal static IGetValue GetPropertyGetterWrapper(PropertyInfo propertyInfo)
 6     {
 7         IGetValue property = (IGetValue)s_getterDict[propertyInfo];
 8         if( property == null ) {
 9             property = CreatePropertyGetterWrapper(propertyInfo);
10             s_getterDict[propertyInfo] = property;
11         }
12         return property;
13     }
14     internal static ISetValue GetPropertySetterWrapper(PropertyInfo propertyInfo)
15     {
16         ISetValue property = (ISetValue)s_setterDict[propertyInfo];
17         if( property == null ) {
18             property = CreatePropertySetterWrapper(propertyInfo);
19             s_setterDict[propertyInfo] = property;
20         }
21         return property;
22     }
23 }
24 public static class PropertyExtensions
25 {
26     public static object FastGetValue(this PropertyInfo propertyInfo, object obj)
27     {
28         if( propertyInfo == null )
29             throw new ArgumentNullException("propertyInfo");
30         return GetterSetterFactory.GetPropertyGetterWrapper(propertyInfo).Get(obj);
31     }
32     public static void FastSetValue(this PropertyInfo propertyInfo, object obj, object value)
33     {
34         if( propertyInfo == null )
35             throw new ArgumentNullException("propertyInfo");
36         GetterSetterFactory.GetPropertySetterWrapper(propertyInfo).Set(obj, value);
37     }
38 }

  说明:我在缓存的设计上并没有使用泛型Dictionary,而是使用了Hashtable。
  我承认在简单的单线程测试中,Dictionary要略快于Hashtable 。

  再来测试一下FastSetValue的性能吧,毕竟大多数时候我会使用这个扩展方法。
  我又在测试代码中增加了一段:

1 propInfo.FastSetValue(testObj, 123);
2 Console.Write("FastSet花费时间:       ");
3 Stopwatch watch6 = Stopwatch.StartNew();
4 for( int i = 0; i < count; i++ )
5     propInfo.FastSetValue(testObj, 123);
6 watch6.Stop();
7 Console.WriteLine(watch6.Elapsed.ToString());

  测试结果如下:

  测试结果表明:虽然通用接口ISetValue将反射性能优化了37倍,但是最终的FastSetValue将这个数字减少到还不到7倍(在CLR4中还不到5倍)。

  看到这个结果您是否也比较郁闷:优化了几十倍的结果,最后却丢了大头,只得到一个零头!

  中间那30倍的时间是哪里消耗了?
  1. Hashtable的查找时间。
  2. 代码的执行路径变长了。

  代码的执行路径变长了,我想所有人应该都能接受:为了简化调用并配合缓存一起工作,代码的执行路径确实变长了。

  Hashtable的查找时间应该很快吧? 您是不是也这样想呢? 
  为了看看Hashtable的查找时间,我又加了一点测试代码:

1 Hashtable table = new Hashtable();
2 table[propInfo] = new object();
3 Console.Write("Hashtable花费时间:      ");
4 Stopwatch watch7 = Stopwatch.StartNew();
5 for( int i = 0; i < count; i++ ) {
6     object val = table[propInfo];
7 }
8 watch7.Stop();
9 Console.WriteLine(watch7.Elapsed.ToString());

  现在运行测试代码的结果如下:

  确实,大部分时间消耗在Hashtable的查找上!

  缓存的线程并发问题

  集合不仅仅只有查找开销,在多线程环境中,我们还要考虑并发性。

  看到许多人做性能测试时,总是喜欢写个控制台程序,然后再来个for循环,执行多少万次!
  我认为 这样的结果只能反映代码在单线程环境下的性能,在多线程下,结果可能会有较大的差别, 当然了,多线程测试的确很复杂,也很难得到准确的数字。 但是我们的设计不能不考虑多线程下的并发问题。

  虽然我也在单线程环境下测试过Dictionary<TKey, TValue>的性能,的确要比Hashtable略好点。
  但是MSDN上对Dictionary的线程安全的描述是这样的:

  此类型的公共静态(在 Visual Basic 中为 Shared)成员是线程安全的。但不能保证任何实例成员是线程安全的。 
  只要不修改该集合,Dictionary<(Of <(TKey, TValue>)>) 就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步。

  而MSDN对Hashtable的线程安全的描述却是:

  Hashtable 是线程安全的,可由多个读取器线程和一个写入线程使用。多线程使用时,如果只有一个线程执行写入(更新)操作,则它是线程安全的,从而允许进行无锁定的读取(若编写器序列化为 Hashtable)。若要支持多个编写器,如果没有任何线程在读取 Hashtable 对象,则对 Hashtable 的所有操作都必须通过 Synchronized 方法返回的包装完成。

  从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。即使一个集合已进行同步,其他线程仍可以修改该集合,这将导致枚举数引发异常。若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。

  显然,二个集合都不能完全支持多线程的并发读写。
  虽然Hashtable提供同步包装的线程安全版本,但是内部还是在使用锁来保证同步的!
  没办法,在多线程环境中,任何复杂数据结构都有线程安全问题。

  如何保证集合在并发操作中数据的同步呢?
  是lock还是ReaderWriterLock?
  显然前者的实现较为简单,所以它成了绝大多数人的首选。
  在.net4中,ConcurrentDictionary是另一个新的首选方法。

  由于Dictionary只支持并发的读操作,所以只要涉及到写操作,它就不安全了,
  因此最安全地做法也只好在 读和写 操作上都加lock,否则就不安全了。

  而Hashtable则不同,它的内部数据结构支持一个线程写入的同时允许多个线程并发读取,所以只要在写操作上加lock就可以实现线程同步, Hashtable的线程安全版本也就是这样实现的。 这也是我选择Hashtable的原因。

  小结

  在这篇博客中,我演示了二种不同的反射优化方法:
  1. 基于Emit的动态生成符合委托签名的IL代码。
  2. 使用Delegate.CreateDelegate直接创建委托。

  这是二种截然不同的思路:
  1. Emit方法,需要先定义一个委托签名,然后生成符合委托签名的IL代码。
  2. CreateDelegate可以直接生成委托,但需要借用泛型类解决委托的类型参数问题,最后为了能通用,需要以接口方式调用强类型委托。

  虽然我们可以使用任何一种方法得到委托,但是我们需要操作多少属性呢? 显然这是一个无解的问题,我们只能为每个属性创建不同的委托。所以新的问题也随之产生: 我们如何保存那些委托?如何让它们与属性关联起来? Dictionary或者Hashtable或许是较好的选择(.net 3.5),然而,这些对象内部的数据结构在查找时,并不是零成本, 它们会消耗优化的大部分成果。 另外,在实现缓存委托的问题上,并发问题也是值得我们考虑的,不高效的并发设计还会让优化的成果继续丢失!

  所以,我认为优化反射是个复杂问题,至少有3个环节是需要考虑的:
  1. 如何得到委托?
  2. 如何缓存委托?
  3. 如何支持并发? 

时间: 2024-10-18 03:06:06

[转] 优化反射性能的总结(上)的相关文章

[转] 优化反射性能的总结(下)

阅读目录 开始 用Delegate优化反射的缺点 用Delegate优化反射的优点 用CodeDOM优化反射的优点 如何用好CodeDOM? 用CodeDOM优化反射的缺点 能不能不使用委托? 根据反射密集程度选择优化方法 CodeDOM优化的误区 反射优化的总结 在前二篇博客中,我分别介绍了二种优化反射的方法:1. Delegate:委托.2. CodeDOM:动态代码生成.这是二种截然不同的方法,性能的差距也很大.今天的博客将着重比较它们的优缺点,以及给出它们的使用建议. 用Delegate

C# 之 反射性能优化

反射是一种很重要的技术,然而它与直接调用相比性能要慢很多,因此如何优化反射性能也就成为一个不得不面对的问题. 目前最常见的优化反射性能的方法就是采用委托:用委托的方式调用需要反射调用的方法(或者属性.字段). 目前最常见也就是二种方法:Emit, ExpressionTree .其中ExpressionTree可认为是Emit方法的简化版本, 所以Emit是最根本的方法,它采用在运行时动态构造一段IL代码来包装需要反射调用的代码, 这段动态生成的代码满足某个委托的签名,因此最后可以采用委托的方式

C# 之 反射性能优化3

阅读目录 开始 用Delegate优化反射的缺点 用Delegate优化反射的优点 用CodeDOM优化反射的优点 如何用好CodeDOM? 用CodeDOM优化反射的缺点 能不能不使用委托? 根据反射密集程度选择优化方法 CodeDOM优化的误区 反射优化的总结 在前二篇博客中,我分别介绍了二种优化反射的方法: 1. Delegate:委托. 2. CodeDOM:动态代码生成. 这是二种截然不同的方法,性能的差距也很大. 今天的博客将着重比较它们的优缺点,以及给出它们的使用建议. 回到顶部

用lambda表达式树优化反射

本节重点不讲反射机制,而是讲lambda表达式树来替代反射中常用的获取属性和方法,来达到相同的效果但却比反射高效. 每个人都知道,用反射调用一个方法或者对属性执行SetValue和GetValue操作的时候都会比直接调用慢很多,这其中设计到CLR中内部的处理,不做深究.然而,我们在某些情况下又无法不使用反射,比如:在一个ORM框架中,你要将一个DataRow转化为一个对象,但你又不清楚该对象有什么属性,这时候你就需要写一个通用的泛型方法来处理,以下代码写得有点恶心,但不妨碍理解意思: //将Da

如何利用缓存机制实现JAVA类反射性能提升30倍

一次性能提高30倍的JAVA类反射性能优化实践 文章来源:宜信技术学院 & 宜信支付结算团队技术分享第4期-支付结算部支付研发团队高级工程师陶红<JAVA类反射技术&优化> 分享者:宜信支付结算部支付研发团队高级工程师陶红 原文首发于宜信支付结算技术团队公号:野指针 在实际工作中的一些特定应用场景下,JAVA类反射是经常用到.必不可少的技术,在项目研发过程中,我们也遇到了不得不运用JAVA类反射技术的业务需求,并且不可避免地面临这个技术固有的性能瓶颈问题. 通过近两年的研究.尝

优化TableView性能

优化tableView性能(针对滑动时出现卡的现象) (2013-08-02 11:18:15) 转载▼ ios tableview it 分类: 技术文档 在iOS应用中,UITableView应该是使用率最高的视图之一了.iPod.时钟.日历.备忘录.Mail.天气.照片.电话.短信. Safari.App Store.iTunes.Game Center?几乎所有自带的应用中都能看到它的身影,可见它的重要性. 然而在使用第三方应用时,却经常遇到性能上的问题,普遍表现在滚动时比较卡,特别是t

HTTP之2 HTTP优化(HTTP性能优化、安全的HTTP协议)

一.HTTP性能优化 HTTP连接过程 HTTP连接性能优化 - 网站性能优化最主要的就是要减少HTTP请求及每次响应中内容的长度.可以从连接过程中的下列方面加以考虑 - 域名解析 尽可能减少域名解析次数---减少跨站外部资源的引用 - 创建连接 努力减少连接创建次数----使用Keep-Alive避免重复连接 - 发送请求 尽力减少请求次数----合理设置Expires时间,资源合并 - 等待响应 提高服务器端运行速度----提高数据运算及查询速度 - 接受响应 尽可能减少响应数据长度---启

[转] 利用表达式树构建委托改善反射性能

最近搞一个系统时由于在比较关键地方用到反射了,所以要关注了一下反射的性能问题.搜索一下,不难搜到老赵的这篇文章,下面是一些杂乱的笔记.(建议先看老赵的文章) .Net4.0反射性能改善 看老赵的文章,老赵得到的结果是这样的: 1 00:00:00.0125539 (Directly invoke) 2 00:00:04.5349626 (Reflection invoke) 3 00:00:00.0322555 (Dynamic executor) 而我把代码搞下来自己运行得到这样的结果: 1

[转]Oracle DB 通过SQL 优化管理性能

? 将SQL 优化指导用于: – 确定使用资源最多的 SQL 语句 – 优化使用资源最多的 SQL 语句 ? 使用SQL 访问指导优化工作量 SQL 优化 SQL 优化进程 ? 确定没有很好地优化的SQL 语句. ? 优化各条语句. ? 优化整个应用程序. 一般情况下,效果最明显的优化工作是SQL 优化.没有很好地优化的SQL 会不必要地使用过多资源.这种低效率会降低可伸缩性.使用更多的OS 和数据库资源并增加响应时间.要对没有很好地优化的SQL 语句进行优化,必须先确定这些语句,然后再进行优化