在 OO 語言寫的程序里面,object 之間最基本的動作是同步功能調(diào)用(synchronous method invocation)。Fast Messenger 編程方法在不改動這個基本動作的前提下,實現(xiàn)了 object 之間的(虛擬)異步功能調(diào)用(asynchronous method invocation)。其基本思想是在兩個 object 之間插入一個中間人 object,然后用兩個同步功能調(diào)用模擬出一個異步功能調(diào)用。FM 將一些眾所周知的編程元素(比如編程模式,編程小竅門等)以創(chuàng)新的方式組織起來,達(dá)到了這個目的。
本文將這些編程元素列舉出來,并配上簡單說明。
OOP原裝的同步功能調(diào)用
同步功能調(diào)用看起來好像就只有一個動作,其實它隱含了好些前提和步驟:
在 object s 中必需要有一個指向 object r 的指針;
在 object s 中必需要有一個正在運(yùn)行的 thread t;
Thread t 使用那個指針調(diào)用 object r 上的 method,進(jìn)而執(zhí)行細(xì)節(jié)步驟:
Thread t 離開 object s,同時進(jìn)入 object r;
Thread t 在 object r 中執(zhí)行那個 method 中的代碼;
Thread t 執(zhí)行完那個 method 后,退出 object r;
Thread t 重新進(jìn)入 object s;
Thread t 回到 object s 后,從剛才離開的地方繼續(xù)運(yùn)行。
示意代碼:
Class S { Class R { R r; // thread t // thread t …… void method (args) { r.method (args); …… …… } } }
Messenger Object
FM 使用了中間人設(shè)計,在 object s 和 r 之間插入了一個 messenger object m。Object m 將 object s 和 r 分隔開,形成兩個區(qū)間:一個包含 object s 和 m;另一個包含 object m 和 r。雖然在同一個區(qū)間里的 object 還是用 OOP 的同步功能調(diào)用來互相動作,但兩個區(qū)間合作起來,卻在 object s 和 r 之間形成了一個虛擬的異步功能調(diào)用。
這個 object m 為 FM 貢獻(xiàn)了兩個重要的基礎(chǔ)。第一個是建立在 object s 和 r 之間的異步特性。當(dāng) object s 調(diào)用 object m 時,object m 將傳過來的參數(shù)保存起來,供稍后處理。這樣,object s 所使用的 thread t1 可以立即返回到 object s。然后在 object m 的內(nèi)部,使用另外的 thread t2 來處理剛才收到的參數(shù),并用它們來調(diào)用 object r。
第二個是給 object r 創(chuàng)建了一個單線程環(huán)境(single-thread context),因為 object m 的位置,使得它可以完全控制進(jìn)入 object r 的線程數(shù)量。這樣 object r 里的代碼可以不用考慮線程安全(thread safe)問題。
示意代碼:
Class S { Class R { Messenger m; // any thread but only one a time R r; void method (args) { // thread t1 …… …… } m.call (r, method, args); } …… }
Object ID
Object m 已經(jīng)去掉了 object s 和 r 之間的一個耦合,因為原先 object s 是直接調(diào)用 object r 的。Object ID 進(jìn)一步去掉了它們間的另一個耦合,現(xiàn)在 object s 都不需要一個指向 object r 的指針了,object s 只需要知道 object r 的 object ID 就夠了。指針是依賴于硬件和所用的 OO 語言的,而 object ID 可以是文本,字符,和數(shù)字等,甚至是人都可以閱讀、理解、和直接使用的。
因為多了一層 ID 到指針的映射關(guān)系(即 mapping 或 binding),object m 需要把所有的映射管理起來。這樣在 object s 用 “r” 來調(diào)用 object r 之前,“r” 到指針 r 的映射必須提前告訴 object m,就如下面的代碼所示。
示意代碼:
Messenger m = new Messenger (); m.register (“r”, r); Class S { Class R { Messenger m; // any thread but only one a time void method (args) { // thread t1 …… …… } m.call (“r”, method, args); } …… }
Message Ports
Object ID 這個概念在 object 和指針之上建立了一個抽象層,這樣在模型這一級,object r 已經(jīng)不存在了,object s 看見的只有 “r”。Message port 是個類似的概念,它在 method 之上建立了一個抽象層。Object s 將用一個 message port (比如下面代碼中的 “x”)來指明它要在 object “r” 上調(diào)用的功能。
如果你熟悉 message passing 的話,可以從另一個角度來理解 message port。FM 不對單個的 message 提供辨認(rèn)的方法,一個 message port 可以用來辨認(rèn)一組類似的 message:它們的數(shù)據(jù)類型,格式,語義等都是一致的。
示意代碼:
Messenger m = new Messenger (); m.register (“r”, r, array of ports); Class S { Class R { Messenger m; // any thread but only one a time void onMessage (port, args) { // thread t1 if (port == “x”) { …… …… m.send (“r”, “x”, args); } else if …… …… } } }
Object ID Instances
Object ID 是個在 object 之上的抽象概念,一個 ID 可以代表一個 object,也可以代表多個 object,甚至其它的什么東西。所以 Object ID instance 里的 instance 特指該 ID 代表的 object 中的一個。這個名字取得不是很好,因為 object 和 instance 在 OOP 里是可以互換的,以后有好的名字再說了。
前面提到的單線程環(huán)境(single-thread context),是應(yīng)用到 instance 這一級的。當(dāng)一個 ID 后面有多個 object (也就是 instance),那么 object m 每次收到一個對該 ID 的調(diào)用請求,都會找一個空閑的 object 用一個不同的線程來調(diào)用。這樣,如果一個 ID 有 N 個 instance 的話,那最多可能有 N 個不同的線程各自在一個 instance 上運(yùn)行。
示意代碼:
Messenger m = new Messenger (); m.register (“r”, array of objects, array of ports); Class S { Class R { Messenger m; // any thread but only one a time void onMessage (port, args) { // thread t1 if (port == “x”) { …… …… m.send (“r”, “x”, args); } else if …… …… } } }