中文MSDN將CallSite<T>譯為“動態(tài)(調(diào)用)站點”,它是DLR中的核心組件之一。
動態(tài)站點對象通過CallSite<T>.Create()方法創(chuàng)建, C#編譯器會為其指定一個派生自CallSiteBinder的對象(稱為“動態(tài)站點綁定對象”)作為其參數(shù)。
動態(tài)站點綁定對象是與具體語言相關的,比如IronPython和C#都有各自的動態(tài)站點綁定對象。
動態(tài)站點綁定對象的主要工作是將代碼中的動態(tài)表達式(本例中為d++)轉(zhuǎn)換為一棵“抽象語法樹(AST:Abstract Syntax Tree)”,這棵語法樹被稱為“DLR Tree”,是在.NET 3.5所引入的LINQ表達式樹的基礎上擴充而來的,因此,有時又稱其為“表達式樹(Expression Tree)”
DLR在內(nèi)部調(diào)用此表達式樹的Compile()方法生成IL指令,得到一個可以被CLR所執(zhí)行的委托(在本例中其類型就是Func<CallSite, object, object>)。
動態(tài)調(diào)用站點對象(本例中為<>p__Site1)有一個Target屬性,它負責引用這一生成好的委托。
委托生成之后,動態(tài)表達式的執(zhí)行就體現(xiàn)為委托的執(zhí)行,其實參由C#編譯器直接“寫死”在IL代碼中。
簡化的代碼示意如下(通過Reflector得到,為便于閱讀,修改了變量名):
object d = 100; object CS$0$0000 = d; if (<>p__Site1 == null) <>p__Site1 = CallSite<Func<CallSite, object, object>>.Create(……); d = <>p__Site1.Target(<>p__Site1, CS$0$0000);
上述類型推斷、方法綁定及IL代碼生成的工作都是在程序運行時完成的。
(4)動態(tài)代碼很慢嗎?
動態(tài)編程語言易學易用,代碼緊湊,開發(fā)靈活,但性能則一直是它的“軟肋”。為了提升性能,DLR設計了一個三級緩存策略。
動態(tài)站點綁定對象會為動態(tài)調(diào)用表達式轉(zhuǎn)換而成的語法樹加上相應的測試條件(稱為“test”),構(gòu)成一個“規(guī)則(Rule)”,這個規(guī)則可以用于判斷某個語法樹是否可用于特定的動態(tài)調(diào)用表達式。
舉個例子,請看以下這個動態(tài)表達式:
d1 + d2
如果在程序運行時d1和d2都是int類型的整數(shù),則DLR生成的規(guī)則為:
if( d1 is int && d2 is int) //測試條件 return (int)d1+(int)d2; //語法樹
DLR通過檢查規(guī)則中的“測試條件”,就可以知道某個動態(tài)表達式是否可以使用此規(guī)則所包容的語法樹。
“規(guī)則”是DLR緩存的主要對象。
前面介紹過的動態(tài)站點對象Target屬性所引用的委托是第一級緩存,它實現(xiàn)的處理邏輯是這樣的:
//當前處理規(guī)則,屬于第1級緩存 if( d1 is int && d2 is int) //測試條件 return (int)d1+(int)d2; //滿足測試條件,直接返回一個表達式樹 //未命中,則在第2級、第3級緩存中查找,如果找到了,用找到的結(jié)果更新第1級緩存 return site.Update(site,d1,d2);
如果3級緩存中都沒有命中的規(guī)則,則此動態(tài)站點所關聯(lián)的調(diào)用站點綁定對象會嘗試創(chuàng)建一個新的規(guī)則。如果創(chuàng)建新規(guī)則失敗,則由當前編程語言(比如C#)所提供的默認調(diào)用站點綁定對象決定如何處理,通常的作法是拋出一個異常。
當前版本的DLR第2級緩存了10條規(guī)則,第3級則緩存了100條規(guī)則。
由于DLR自身設計了一個“規(guī)則”緩存系統(tǒng),又充分利用了CLR所提供的JIT緩存(因為所有動態(tài)調(diào)用代碼最終都會轉(zhuǎn)換為CLR可以執(zhí)行的IL指令,而CLR可以緩存這些代碼),使得動態(tài)代碼僅僅在第一次執(zhí)行時性能較差,后續(xù)的連續(xù)調(diào)用其性能可以逼近靜態(tài)代碼。
出處:CSDN
責任編輯:bluehearts
上一頁 拓展動態(tài)編程的新領域 [3] 下一頁 拓展動態(tài)編程的新領域 [5]
◎進入論壇網(wǎng)絡編程版塊參加討論
|