前段時間一直周旋於各種有趣且辛苦, 或者無趣且更辛苦的事情當中, 雖然其間也切換到其他好些不同的技術領域, 但一直沒有放棄在AOP方面的關注思考. 前面之所以沒有能接著AOP這個話題繼續和大家聊下去, 是因為感覺自己沒有足夠的精力和空閑來將這些想法沉澱下來, 並回鍋為簡單直白, 易於消化和理解, 並能引發思考的東西. 這幾天, 出差在外, 工作之餘免去了灶台內外的忙活. 油煙味少了, 人也覺得清爽許多; 閑暇多了, 就免不了想爬爬格子. OK, 閑話到此為止, 就讓我們繼續AOP的白話之旅吧J 簡單回顧一下前一段旅程(一,二,三), 在前面我們簡要介紹了什麼是Agent, 這個東東的來由, 以及與其他重要概念, 如Object的區別. 如果說前段理論之旅展現的奇異風光令我們心神蕩漾, 那麼接下來的實踐之旅就會又把我們拽回到繁雜而精密的軟體世界中. 在前面也有介紹過, 目前好像還沒有一個專門針對AOP的IDE, 這對於急於操練一把AOP的同志來說是個不大不小的尷尬. 不過好在Agent也是由Object脫胎而來, 基於目前的OOP語言, 我們也可以來過一把AOP的癮. 這裡我們選擇的是.Net 平台下的C#. 為什麼要選擇C#,,,, 因為如果使用Java, 文章也就不會發在這裡, just jokingJ 理論上說, 任何OOP語言, Java, Delphi, C++, 都可以作為哈裡.傳輸速率同學手中的魔法棒, 點化出妙不可言的Agent. 之所以選擇C#, 是看中他的優雅和簡潔(補充一句, 直到現在俺依然固執地認為Delphi是最優雅的語言, 雖然Borland迫於生計不得不出售整個IDE部門, 但俺依然決意守望Delphi, 直到Delphi的桅杆沒入海平面的最後一刻…) 翻翻講述Agent理論的書籍就可以查到, 一個為理論界所接受的Agent需要具有如下若干特徵: l 代理性(Action On Behalf Others)l 自製性(Autonomy) l 主動性(Proactivity) l 反應性(Reactivity)l 社會性(Social Ability) l 智能性(Intelligence) l 合作性(Callaboration) l 移動性(Mobility) My god! 光把這些名詞理解一遍就讓人頭大了. 不多解釋了. 簡單點, Simple is good. 我們現在不需要迎合理論家挑剔的口味, 只需要創造一個具有不完全特性的Agent. 女媧同學造人的時候還不是就地取材, 捧著坨泥巴就捏上了J 另一方面, 作為整個AgentWorld的締造者, 我們必需意識到這樣一點: 上述這些特性, 是分層次的, 比如反應性, 和自製性, 這應該是位於Agent心智(Mind)最底層的特性; 而社會性, 智能性, 合作性等, 則應該屬於Agent的進階心智, 需要其他心智能力的支援. 在由混沌到開天地的最初步驟中, 我們只需要實現最低層次的Agent心智即可. 綜合以上考慮, 在我們捏出的第一個Agent身上, 可以看到如下幾種心智:l 同步非同步統一和同類群組l 對外界變化的感知l 時間驅動l 移動性 下面我們來逐一審視這些貌似簡單, 卻可能蘊含無限組合及演化能量的心智要素.
同步非同步統一和同類群組前面聊到說, 我們有認識到Object世界存在著”同步和非同步被人為地剝離”的尷尬, “同步非同步統一和同類群組”則是Agent世界對這一尷尬的解答. 在我們的Agent世界中, Agent A1呼喚Agent A2協助其做某件工作M1, 並不需要瞭解到A2做這件事情是同步在做還是非同步在做, 這是同步非同步統一; 更進一步, 如果這件事情, 和A2具有同樣能力的好幾個Agent都可以來做, 那麼A1更不需要知道到底是哪一個具體的”A2”在做這件工作. 有點抽象噢? Ok, 這好比現實生活中的一個例子: 領導曰”上午10點讓司機過來接我去開會”. 領導作為一個Agent, 他不需要瞭解司機這種Agent 10點開車到樓下是同步行為還是非同步行為(當然司機自己要清楚), 也不需要瞭解開車過來的是單位上的哪個司機, 小王or小張? 這是領導需要關心的事情嗎? 他只需要知道10點下樓, 就有個司機在那候著. 用程式語言來描述: Boss的執行代碼就是:driver.ComeHere(10:00) Driver的代碼:class Driver : Agent_XXX{ [AgentMethod(AgentMethodCallMode.Asyn, AgentMethodRouteMode.Group)] public virtual void ComeHere(DateTime time){…} …} Ok, 讓我們把所有注意力都集中到藍色的Attribute上, 這是Driver這個Agent類在”同步非同步統一和同類群組”這種心智上的體現. 為什麼我們剛才說要選擇C#這種優雅的語言, 就是因為我們可以使用Attribute這個特性來將Agent的心智附著在普通的Object Class上. 當然, 我們也可以額外地用一個描述心智要素的XML檔案來和Class綁定, 但個人感覺而言, Attribute來的更加優雅直接一些. AgentMethod, 這個屬性工作表明, ComeHere這個Method, 是Driver這個Agent的一種能力, 注意是能力不是心智. 這種能力帶了特定的心智資訊: l AgentMethodCallMode.Asyn
這個Attribute表明這種能力是非同步呼叫的, 而非同步. 看到這裡有些同志不免生疑, 不是說同步和非同步不再區分的嘛, 怎麼還有Asyn, Syn這樣的標記呢? 不爽! 解釋一把, 我們所說的同步和非同步不再區分, 是從調用者的角度考察, 比如領導之於司機, 老師之於學生. 而對於方法的被調用者, 也就是實際執行者來說, 他當然是需要”內心”裡知曉這個方法到底是如何完成的. 實際上在領導調用driver.ComeHere(10:00)之後, 領導所擁有的心智, 即線程馬上可以接下去做其他事情, 而ComeHere(10:00)這個方法, 則被轉移到某個Driver執行個體的心智, 即線程上去執行.
這裡的一個小小差異, 實際上凸現出Agent和Object的一個很大區別: 在Agent世界中, 每個Agent只需要關注自己邏輯是如何執行的, 而對其他Agent的邏輯執行細節的關注, 被降低到的最低.
如果有同志覺得上面這段話過於抽象, ok, 讓我們更技術化的語言重複一次: 每個Agent都帶有一個獨立的線程(我們可以把它理解為Agent的靈魂J), 每個Agent自身的能力(在OOP語言環境下被映射為Method)都在這個線程上來被解釋和執行. 如果一個行為序列包含有若干不同Agent的能力的執行, 那麼完成這個行為序列就會使用到好幾個不同的線程, 並且線程之間的切換是完全透明和自動的.
深入到技術細節之後, 讓我們趕緊上浮到更宏觀的一個層面上來, 否則很快就會在對技術細節的探究中失去對Agent設計理念的把握能力. 現在我們已經知道: 一個Agent, 它所擁有的能力(也就是各種Method)只能由它擁有的靈魂(也就是其獨佔的線程)來執行. 那麼顯然的一個問題是: 這帶來了什麼樣的益處?
l AgentMethodRouteMode.Group.
這個Attribute表明Boss要一輛車, 這個請求, 是一個群組請求, 而不是針對某個Driver類的某個具體執行個體. 這個請求會被放到一個基於群組(也就是具有共同能力的一類Agent)的請求池中, 假設此時單位有三位司機空閑, 那麼其中的一位就會接受到這個請求, 隨後執行之. 這應該是對Agent理論中黑板模型的一個最最簡單的實現: 有什麼請求, 寫到一個黑板上, 有能力響應這個請求的, 就來處理, 並把這個請求從黑板上擦掉.
大家可以想像一下這種心智的用場何在. 先往現實世界中靠, 找找現實世界中是否存在這種例子? 大量存在, 銀行櫃檯業務, 逾時購物結算. 再回到軟體世界中, 我們很容易聯想起一個詞: Server Load BalancerJ 如果具有某種能力(能夠執行某種關鍵業務操作)的Agent通過Mobility心智(稍後會介紹方面內容)分布在整個系統的若干台不同機器上, 同時共用同一個群組請求池, 外部進來的業務操作請求進入請求池後, 就會為不同機器上的Agent所處理. Server Load Balancer乎J 當然, 誰說現在銀行系統不是Server Load Balancer的? 我們這裡強調的是: 在Agent世界中實現Server Load Balancer的簡潔性. 僅僅需要一個Attribute, 並且, 由於底層的群組請求池是系統自動構造的, 因此如果需要進一步平衡負載, 只需要多new幾個 driver, 並把他們移動到不同的機器上, 就好比銀行裡看到排隊的人多了, 臨時增加幾個業務視窗的道理一樣. 很重要的一點, Agent世界裡能實現的, Obejct世界或者彙編世界裡同樣都可以實現, 我們看重的是實現的簡潔性(偷懶性?)及於現實世界貼近的程度.
AgentMethod還有好幾種組合, 這裡就不一一介紹了, 陷入編碼細節的討論必然會妨礙我們對概念整體上的把握. 但這裡不得不說明的是, 假設Boss需要driver在達到之後通知他一下, 應該怎麼實現呢? 由於OOP的限制, 我們不得不使用一種相當不優雅的方式: 回呼函數, 來解決這個問題. 於是乎, 在Boss這個Agent類中會出現如下代碼: [CallBackMethodAttribute(typeof(driver), "ComeHere")]public virtual void CallBack_Driver_ComeHere(Message_ResultOfASYNCallMethod message){…} 這裡的CallBackMethodAttribute表明, 當某個Driver達到樓下後, 會自動(對於Driver和Boss來說都是透明的)調用這個方法. 注意, 這個方法的執行, 是在Boss的心智中, 而不是由Driver來完成的, 也就是說, 系統會自動在Driver的線程中執行ComeHere操作, 隨後又自動切換到Boss的線程, 來執行CallBack_Driver_ComeHere. 想像一下, 為什麼會這樣 and 為什麼要這樣? J
要不今天咱們就整到這裡, 如果大家有興趣的話, 下面的章節中, 我們會接著聊聊感知力, 時間驅動, 移動性等更好玩的話題. 整點小思考題, 注意到Agent類的每個方法上都帶有virtual指示符, why? 借用Matrix中的一句話:”There is something different.”, 其實, 剛才咱們所聊的所有內容, 包括今後旅途中所看到的Agent World中大多數風景, 都位於水平面之上, 而順著這個隱秘的線索深入下去, 您就能觸摸到Agent World位於水平面之下龐大而精密的支撐架構. 水面之下, 沒有任何風景, 只有高速運轉的調度線程, 吞吐繁忙的緩衝池, 張合有序的讀寫鎖, 以及無處不在的BugJ