程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> ASP.NET基礎 >> 淺談.NET反射機制的性能優化 附實例下載

淺談.NET反射機制的性能優化 附實例下載

編輯:ASP.NET基礎
可能大家談到反射面部肌肉都開始抽搐了吧!因為在托管語言裡面,最臭名昭著的就是反射!它的性能實在是太低了,甚至在很多時候讓我們無法忍受。不過不用那麼糾結了,老陳今天就來分享一下如何來優化反射!

概述
本文涉及到的反射優化的途徑有如下兩種:

通過Delegate.CreateDelegate()創建委托進行優化
通過.NET4的動態運行時進行優化
如果您還知道其他更加有效的優化途徑,請不吝賜教!

准備工作
今天我們總計要對比五種不同的調用對象成員的方式,也算是一種性能測評。

在開始之前,我們首先定義一個簡單的對象和一個方法,以供測試之用:
復制代碼 代碼如下:
namespace ReflectionOptimization
{
public sealed class TestObject
{
public int Add(int a, int b)
{
// 簡單演示
return a + b;
}
}
}

這個類非常簡單,只提供了一個方法,這個方法返回兩個整形的和。接下來我們看看執行時間測量的代碼,很簡單,想必您已經駕輕就熟了:
復制代碼 代碼如下:
private static double _Run(string description, Action<int, int> action, int a, int b)
{
if (action == null) throw new ArgumentNullException("action");

// 啟動計時器
var stopwatch = Stopwatch.StartNew();

// 運行要測量的代碼
action(a, b);

// 終止計時
stopwatch.Stop();

// 輸出結果
Console.WriteLine("{0}: {1}", description, stopwatch.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));

// 返回執行時間
return stopwatch.Elapsed.TotalMilliseconds;
}

以上測量時間的方法返回了執行時間,因為我們要在後面用到這個值,在執行多次之後取個平均值,以求測試的公平性、權威性。

編碼實現
首先我們來看看原生反射的實現:
復制代碼 代碼如下:
var obj = new TestObject();
var add = obj.GetType().GetMethod("Add");

for (var i = 0; i < _TIMES; i++) add.Invoke(obj, new object[] {a, b});

然後我們看看.NET4動態編程的實現:
復制代碼 代碼如下:
dynamic obj = new TestObject();

// 有木有發現這個代碼超級簡單?
for (var i = 0; i < _TIMES; i++) obj.Add(a, b);

最後我們看看如何使用委托來優化反射:
復制代碼 代碼如下:
// 委托
public delegate int AddMethod(int a, int b);

// 實現
var obj = new TestObject();
var objType = obj.GetType();
var add = objType.GetMethod("Add");
var d = (AddMethod)Delegate.CreateDelegate(typeof(AddMethod), obj, add);

for (var i = 0; i < _TIMES; i++) d(a, b);

上面的代碼看起來多了幾行,而且還需要自定義一個委托,寫起來挺麻煩的。因此我們的測試代碼裡面還實現了另外一種形式,其實它也是委托:

var d = (Func<TestObject, int, int, int>)Delegate.CreateDelegate(typeof(Func<TestObject, int, int, int>), add);

測試總結
我們首先在Debug模式下將整個測試代碼運行5遍,然後分別記錄平均值,然後再到Release模式下重復該測試。

測試的過程不再闡述,測試結果整理如下:

Debug模式:

調用方式 第一次 第二次 第三次 第四次 第五次 Generic Call 1.022425 1.012885 0.990775 1.020950 1.046880 Reflection 147.489220 146.012010 142.690080 139.189335 141.663475 dynamic 9.645850 9.979965 9.307235 9.532665 9.730030 Func 1.201860 1.214800 1.170215 1.189280 1.239485 Delegate 1.062215 1.061635 1.067510 1.047180 1.075190

Release模式:

調用方式 第一次 第二次 第三次 第四次 第五次 Generic Call 0.745600 0.741365 0.722145 0.732630 0.725645 Reflection 141.778260 142.855410 142.346095 139.649990 138.541285 dynamic 9.631460 10.341850 9.284230 9.457580 9.060470 Func 0.882100 0.852680 0.875695 0.854655 0.831670 Delegate 0.710280 0.722465 0.723355 0.727175 0.693320

點評&結論:

  • 使用委托優化反射之後,其性能與直接調用相差無幾,保持在同一個數量級之內,對性能要求極度苛刻時推薦此方案;
  • 顯式委托(Delegate)和匿名委托(Func)性能差異非常不明顯,但顯式委托的性能還是好一點; 
  • 原生委托比直接調用慢出了兩個數量級,性能差異達到了200倍之多!
  • .NET 4的動態編程語法相當簡潔,其性能只比直接調用高出一個數量級,由於其語法相當簡潔,我們推薦這種做法!
  • 原生反射技術在Debug模式和Release模式下沒有太大差異,但其他方式有較為明顯的優化效果(請思考為什麼);
  • 雖然我們今天的測試不能完全意味著反射優化之後可以和直接調用相媲美,但至少可以從某種程度上擊敗那些個謠言——誰說反射就一定會慢(嘻嘻)!

代碼下載:淺談反射優化
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved