因為項目中需要用到反射,而單純反射據說性能很低,所以就想到了優化反射.而關於反射的優化方案園子里面有不少大牛都已經提出來詳細的解決方案,這個就不詳細說了,想了解的可以具體看這里http://www.cnblogs.com/fish-li/category/453548.html.文章里面提到了通過創建委托來提高反射性能.
既然有了解決方案,那就來吧.
項目中主要用反射來操作對象屬性,所以就先不考慮方法的反射了
使用Emit構造委托
1 public delegate object FastGetMethod(object arg);//定義委托類型 2 public static class FastReflection 3 { 4 /// <summary> 5 /// 緩存委托集合 6 /// </summary> 7 private static ConcurrentDictionary<string, FastGetMethod> _getMethods = new ConcurrentDictionary<string, FastGetMethod>(); 8 public static FastGetMethod FastGetMethod(PropertyInfo property) 9 { 10 FastGetMethod getMethod; 11 if (!_getMethods.TryGetValue(string.Concat(property.DeclaringType.FullName, "_", property.Name), out getMethod)) 12 { 13 getMethod = FastReflection.GetGetMethod(property); 14 _getMethods.TryAdd(string.Concat(property.DeclaringType.FullName, "_", property.Name), getMethod); 15 } 16 return getMethod; 17 } 18 private static FastGetMethod GetGetMethod(PropertyInfo property) 19 { 20 if (property == null) 21 { 22 throw new ArgumentNullException("property"); 23 } 24 if (!property.CanRead) 25 { 26 return null; 27 } 28 MethodInfo method = property.GetGetMethod(true); 29 DynamicMethod dm = new DynamicMethod("GetValueMethod", typeof(object), new Type[] { typeof(object) }, property.DeclaringType, true); 30 ILGenerator il = dm.GetILGenerator(); 31 if (!method.IsStatic) 32 { 33 il.Emit(OpCodes.Ldarg_0); 34 il.EmitCall(OpCodes.Callvirt, method, null); 35 } 36 else 37 { 38 il.EmitCall(OpCodes.Call, method, null); 39 } 40 if (property.PropertyType.IsValueType) 41 { 42 il.Emit(OpCodes.Box, property.PropertyType); 43 } 44 il.Emit(OpCodes.Ret); 45 return (FastGetMethod)dm.CreateDelegate(typeof(FastGetMethod)); 46 } 47 }
如此,就來測試一下吧
測試代碼如下
class Person { public string Name { get; set; } public int Age { get; set; } } //調用代碼 Person p = new Person() { Age = 100, Name = "Hello Test" }; PropertyInfo info = (typeof(Person)).GetProperty("Age"); int times = 100 * 100 * 100;//調用1000000次 int temp1 = 0, temp2 = 0; Console.WriteLine("調用{0}次比較", times); Stopwatch watch1 = new Stopwatch(); watch1.Start(); FastGetMethod getMethod = FastReflection.FastGetMethod(info); for (int i = 0; i < times; i++) { temp1 = (int)getMethod(p); } watch1.Stop(); Console.WriteLine("FastReflection耗時:{0}", watch1.Elapsed); Stopwatch watch2 = new Stopwatch(); watch2.Start(); for (int i = 0; i < times; i++) { temp2 = (int)info.GetValue(p, null); } watch2.Stop(); Console.WriteLine("直接反射耗時:{0}",watch2.Elapsed);
在release模式下
可以看到性能上確實有了很大差別
到這里似乎就算是完了,可以突然想看看單次調用時性能上的差別有多少
結果卻有點出乎意料,單次調用時優化的反而比不上未優化的,讓人無法接受啊,是什么原因導致的呢?想到構建委托時要消耗性能,那就看下創建委托是需要的時間吧
可以看到構建委托時確實消耗不少性能,可是在接下來的調用還是有着巨大的差別,這是怎么一回事?單次調用直接反射有着巨大優勢,可是在多次調用是反而要比通過委托來調用,這究竟是怎么一回事呢?這個讓我很迷茫,這樣做到底算不算的上是優化?一個項目中一次請求中可能只掉用幾次反射,沒有像測試這樣一次性調用這么多次,那是否需要去反射呢?希望可以有高人幫忙解答下