在 OO 語言寫的程序里面,object 之間最基本的動(dòng)作是同步功能調(diào)用(synchronous method invocation)。Fast Messenger 編程方法在不改動(dòng)這個(gè)基本動(dòng)作的前提下,實(shí)現(xiàn)了 object 之間的(虛擬)異步功能調(diào)用(asynchronous method invocation)。其基本思想是在兩個(gè) object 之間插入一個(gè)中間人 object,然后用兩個(gè)同步功能調(diào)用模擬出一個(gè)異步功能調(diào)用。FM 將一些眾所周知的編程元素(比如編程模式,編程小竅門等)以創(chuàng)新的方式組織起來,達(dá)到了這個(gè)目的。
本文將這些編程元素列舉出來,并配上簡(jiǎn)單說明。
OOP原裝的同步功能調(diào)用
同步功能調(diào)用看起來好像就只有一個(gè)動(dòng)作,其實(shí)它隱含了好些前提和步驟:
在 object s 中必需要有一個(gè)指向 object r 的指針;
在 object s 中必需要有一個(gè)正在運(yùn)行的 thread t;
Thread t 使用那個(gè)指針調(diào)用 object r 上的 method,進(jìn)而執(zhí)行細(xì)節(jié)步驟:
Thread t 離開 object s,同時(shí)進(jìn)入 object r;
Thread t 在 object r 中執(zhí)行那個(gè) method 中的代碼;
Thread t 執(zhí)行完那個(gè) 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è)計(jì),在 object s 和 r 之間插入了一個(gè) messenger object m。Object m 將 object s 和 r 分隔開,形成兩個(gè)區(qū)間:一個(gè)包含 object s 和 m;另一個(gè)包含 object m 和 r。雖然在同一個(gè)區(qū)間里的 object 還是用 OOP 的同步功能調(diào)用來互相動(dòng)作,但兩個(gè)區(qū)間合作起來,卻在 object s 和 r 之間形成了一個(gè)虛擬的異步功能調(diào)用。
這個(gè) object m 為 FM 貢獻(xiàn)了兩個(gè)重要的基礎(chǔ)。第一個(gè)是建立在 object s 和 r 之間的異步特性。當(dāng) object s 調(diào)用 object m 時(shí),object m 將傳過來的參數(shù)保存起來,供稍后處理。這樣,object s 所使用的 thread t1 可以立即返回到 object s。然后在 object m 的內(nèi)部,使用另外的 thread t2 來處理剛才收到的參數(shù),并用它們來調(diào)用 object r。
第二個(gè)是給 object r 創(chuàng)建了一個(gè)單線程環(huán)境(single-thread context),因?yàn)?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 之間的一個(gè)耦合,因?yàn)樵?object s 是直接調(diào)用 object r 的。Object ID 進(jìn)一步去掉了它們間的另一個(gè)耦合,現(xiàn)在 object s 都不需要一個(gè)指向 object r 的指針了,object s 只需要知道 object r 的 object ID 就夠了。指針是依賴于硬件和所用的 OO 語言的,而 object ID 可以是文本,字符,和數(shù)字等,甚至是人都可以閱讀、理解、和直接使用的。
因?yàn)槎嗔艘粚?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 這個(gè)概念在 object 和指針之上建立了一個(gè)抽象層,這樣在模型這一級(jí),object r 已經(jīng)不存在了,object s 看見的只有 “r”。Message port 是個(gè)類似的概念,它在 method 之上建立了一個(gè)抽象層。Object s 將用一個(gè) message port (比如下面代碼中的 “x”)來指明它要在 object “r” 上調(diào)用的功能。
如果你熟悉 message passing 的話,可以從另一個(gè)角度來理解 message port。FM 不對(duì)單個(gè)的 message 提供辨認(rèn)的方法,一個(gè) 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 是個(gè)在 object 之上的抽象概念,一個(gè) ID 可以代表一個(gè) object,也可以代表多個(gè) object,甚至其它的什么東西。所以 Object ID instance 里的 instance 特指該 ID 代表的 object 中的一個(gè)。這個(gè)名字取得不是很好,因?yàn)?object 和 instance 在 OOP 里是可以互換的,以后有好的名字再說了。
前面提到的單線程環(huán)境(single-thread context),是應(yīng)用到 instance 這一級(jí)的。當(dāng)一個(gè) ID 后面有多個(gè) object (也就是 instance),那么 object m 每次收到一個(gè)對(duì)該 ID 的調(diào)用請(qǐng)求,都會(huì)找一個(gè)空閑的 object 用一個(gè)不同的線程來調(diào)用。這樣,如果一個(gè) ID 有 N 個(gè) instance 的話,那最多可能有 N 個(gè)不同的線程各自在一個(gè) 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 …… …… } } }