淺談.NET反射機(jī)制的性能優(yōu)化 附實(shí)例下載
概述
本文涉及到的反射優(yōu)化的途徑有如下兩種:
通過Delegate.CreateDelegate()創(chuàng)建委托進(jìn)行優(yōu)化
通過.NET4的動(dòng)態(tài)運(yùn)行時(shí)進(jìn)行優(yōu)化
如果您還知道其他更加有效的優(yōu)化途徑,請(qǐng)不吝賜教!
準(zhǔn)備工作
今天我們總計(jì)要對(duì)比五種不同的調(diào)用對(duì)象成員的方式,也算是一種性能測(cè)評(píng)。
在開始之前,我們首先定義一個(gè)簡單的對(duì)象和一個(gè)方法,以供測(cè)試之用:
namespace ReflectionOptimization
{
public sealed class TestObject
{
public int Add(int a, int b)
{
// 簡單演示
return a + b;
}
}
}
這個(gè)類非常簡單,只提供了一個(gè)方法,這個(gè)方法返回兩個(gè)整形的和。接下來我們看看執(zhí)行時(shí)間測(cè)量的代碼,很簡單,想必您已經(jīng)駕輕就熟了:
private static double _Run(string description, Action<int, int> action, int a, int b)
{
if (action == null) throw new ArgumentNullException("action");
// 啟動(dòng)計(jì)時(shí)器
var stopwatch = Stopwatch.StartNew();
// 運(yùn)行要測(cè)量的代碼
action(a, b);
// 終止計(jì)時(shí)
stopwatch.Stop();
// 輸出結(jié)果
Console.WriteLine("{0}: {1}", description, stopwatch.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
// 返回執(zhí)行時(shí)間
return stopwatch.Elapsed.TotalMilliseconds;
}
以上測(cè)量時(shí)間的方法返回了執(zhí)行時(shí)間,因?yàn)槲覀円诤竺嬗玫竭@個(gè)值,在執(zhí)行多次之后取個(gè)平均值,以求測(cè)試的公平性、權(quán)威性。
編碼實(shí)現(xiàn)
首先我們來看看原生反射的實(shí)現(xiàn):
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動(dòng)態(tài)編程的實(shí)現(xiàn):
dynamic obj = new TestObject();
// 有木有發(fā)現(xiàn)這個(gè)代碼超級(jí)簡單?
for (var i = 0; i < _TIMES; i++) obj.Add(a, b);
最后我們看看如何使用委托來優(yōu)化反射:
// 委托
public delegate int AddMethod(int a, int b);
// 實(shí)現(xiàn)
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);
上面的代碼看起來多了幾行,而且還需要自定義一個(gè)委托,寫起來挺麻煩的。因此我們的測(cè)試代碼里面還實(shí)現(xiàn)了另外一種形式,其實(shí)它也是委托:
var d = (Func<TestObject, int, int, int>)Delegate.CreateDelegate(typeof(Func<TestObject, int, int, int>), add);
測(cè)試總結(jié)
我們首先在Debug模式下將整個(gè)測(cè)試代碼運(yùn)行5遍,然后分別記錄平均值,然后再到Release模式下重復(fù)該測(cè)試。
測(cè)試的過程不再闡述,測(cè)試結(jié)果整理如下:
Debug模式:
| 調(diào)用方式 | 第一次 | 第二次 | 第三次 | 第四次 | 第五次 |
|---|---|---|---|---|---|
| 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模式:
| 調(diào)用方式 | 第一次 | 第二次 | 第三次 | 第四次 | 第五次 |
|---|---|---|---|---|---|
| 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 |
點(diǎn)評(píng)&結(jié)論:
- 使用委托優(yōu)化反射之后,其性能與直接調(diào)用相差無幾,保持在同一個(gè)數(shù)量級(jí)之內(nèi),對(duì)性能要求極度苛刻時(shí)推薦此方案;
- 顯式委托(Delegate)和匿名委托(Func)性能差異非常不明顯,但顯式委托的性能還是好一點(diǎn);
- 原生委托比直接調(diào)用慢出了兩個(gè)數(shù)量級(jí),性能差異達(dá)到了200倍之多!
- .NET 4的動(dòng)態(tài)編程語法相當(dāng)簡潔,其性能只比直接調(diào)用高出一個(gè)數(shù)量級(jí),由于其語法相當(dāng)簡潔,我們推薦這種做法!
- 原生反射技術(shù)在Debug模式和Release模式下沒有太大差異,但其他方式有較為明顯的優(yōu)化效果(請(qǐng)思考為什么);
- 雖然我們今天的測(cè)試不能完全意味著反射優(yōu)化之后可以和直接調(diào)用相媲美,但至少可以從某種程度上擊敗那些個(gè)謠言——誰說反射就一定會(huì)慢(嘻嘻)!
代碼下載:淺談反射優(yōu)化
相關(guān)文章
asp.net中button控制先執(zhí)行js再執(zhí)行后臺(tái)程序的方法
這篇文章主要介紹了asp.net中button控制先執(zhí)行js再執(zhí)行后臺(tái)程序的方法,涉及button控件與js的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01
asp.net DataList與Repeater用法區(qū)別
Repeater比DataList要好一些,如果不是很大數(shù)據(jù)量的話,這點(diǎn)差別是體現(xiàn)不來的。2009-12-12
獲取遠(yuǎn)程網(wǎng)頁的內(nèi)容之二(downmoon原創(chuàng))
獲取遠(yuǎn)程網(wǎng)頁的內(nèi)容之二(downmoon原創(chuàng))...2007-03-03
asp.net Repeater綁定時(shí)使用函數(shù)
asp.net repeater綁定函數(shù)使用實(shí)例2008-08-08
.NET Core 2.0遷移小技巧之MemoryCache問題修復(fù)解決的方法
這篇文章主要給大家介紹了關(guān)于.NET Core 2.0遷移小技巧之MemoryCache問題修復(fù)解決的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08
asp.net下數(shù)據(jù)庫操作優(yōu)化一例
數(shù)據(jù)庫升級(jí),需要對(duì)幾個(gè)表進(jìn)行一些數(shù)據(jù)轉(zhuǎn)換,具體是這樣:針對(duì)每一個(gè) Item,從 orders 表里查出 Shop_Id,并把此 Id 賦值給 items 和 skus 中的 Shop_Id。2010-11-11
asp.net中通過DropDownList的值去控制TextBox是否可編寫的實(shí)現(xiàn)代碼
Web窗體上有兩控件,DropDownList1,TextBox1,當(dāng)DropDownList的值選擇是YES的時(shí)候,TextBox1可編輯,當(dāng)選擇NO的時(shí)候,TextBox1的值為空,并且不能編輯,該如何實(shí)現(xiàn)2012-11-11
ASP.NET頁面請(qǐng)求超時(shí)時(shí)間設(shè)置多種方法
這篇文章主要為大家詳細(xì)介紹了ASP.NET頁面請(qǐng)求超時(shí)時(shí)間設(shè)置Server.ScriptTimeOut executionTimeout多種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
.NET使用DinkToPdf將HTML轉(zhuǎn)成PDF的示例代碼
這篇文章主要介紹了.NET使用DinkToPdf將HTML轉(zhuǎn)成PDF的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02

