我是一個(gè)函數(shù),生活在內(nèi)存當(dāng)中
我是一個(gè)函數(shù), 生活在內(nèi)存當(dāng)中,我的家--用你們的“黑話”來(lái)說(shuō)--就是進(jìn)程的地址空間, 我的鄰居也是一個(gè)函數(shù),其中有一段很有趣的代碼。
我經(jīng)常去拜訪他,去的時(shí)候當(dāng)然不能空著手,我會(huì)攜帶四個(gè)數(shù)字作為禮物送給他計(jì)算, 耐心等待他在CPU中忙活半天,最后,作為回贈(zèng)的禮物,他告訴我一個(gè)地址,讓我去那里取結(jié)果。
拜訪的次數(shù)多了,我慢慢地琢磨出了我這個(gè)鄰居做的事情: 房貸計(jì)算。
我給他發(fā)的四個(gè)參數(shù)分別是房貸總額,利率,貸款年限,還款方式(等額本息是1, 等額本金是2) 他告訴我的是一個(gè)地址,其實(shí)就是一個(gè)列表,存放著每個(gè)月應(yīng)還的月供、本金和利息。
用你們的“黑話”來(lái)說(shuō)就是這樣:
List calculateHouseLoan(float total, float intrestRate, int years ,int loanType)
所有的調(diào)用都發(fā)生在本機(jī)內(nèi)的一個(gè)進(jìn)程中, 大家把這種方式稱為本地過(guò)程調(diào)用。
這種調(diào)用方式速度飛快,眨眼間就可完成。
有時(shí)候,房貸計(jì)算鄰居會(huì)驚呼道: 我賽,你給我發(fā)了一個(gè)多大的數(shù)啊, 800萬(wàn)的貸款總額!
我就知道,帝都的房?jī)r(jià)又漲了!
日子過(guò)了一天又一天, 房?jī)r(jià)也漲了一天又一天。
一天早上, 我睡了一覺(jué)醒來(lái)感覺(jué)不太對(duì)勁,頭暈暈的,一般情況下這就表示昨天夜里系統(tǒng)重啟了。
還沒(méi)等我清醒過(guò)來(lái), 我就接到上司(調(diào)用我的函數(shù))的命令,又要計(jì)算房貸了,我忍著頭暈趕緊去找鄰居,可是這一次卻換成了陌生人, 他笑瞇瞇的說(shuō):“是不是要找你的鄰居房貸計(jì)算啊”
“是啊”
“他已經(jīng)搬走了!”
“啊? 他搬到哪兒去了? 我怎么計(jì)算房貸? ”
“ 他搬到另外一臺(tái)機(jī)器去住了,具體位置我也不清楚,不過(guò)從IP看應(yīng)該是在同一個(gè)機(jī)房吧”
說(shuō)實(shí)話這個(gè)消息讓我吃驚不小,我聽(tīng)人說(shuō)過(guò),想和網(wǎng)絡(luò)上的機(jī)器通信,那可比本機(jī)的同一進(jìn)程內(nèi)的通信麻煩太多了。
之前我們生活在同一個(gè)進(jìn)程中,每個(gè)函數(shù)的住處(地址)對(duì)大家來(lái)說(shuō)都是可見(jiàn)的,想要調(diào)用了,直接去函數(shù)的住處去執(zhí)行代碼即可。
現(xiàn)在這個(gè)函數(shù)都搬走了,新的地址我也不知道,就是知道了,跨域網(wǎng)絡(luò)的調(diào)用,據(jù)說(shuō)得使用什么socket,建立連接,在連接上按雙方商量好格式、次序來(lái)發(fā)送數(shù)據(jù), 接收數(shù)據(jù),聽(tīng)著就頭大, 打死我也搞不定。
(碼農(nóng)翻身老劉注: socket的故事參見(jiàn)《張大胖和socket》)
陌生人看出了我的擔(dān)心, 笑著說(shuō): “放心吧, 我是他的客戶端代理,你盡管把那四個(gè)參數(shù)交給我,我來(lái)幫你搞定”
這家伙自稱為客戶端代理的家伙竟然知道那個(gè)四個(gè)參數(shù),也許能行,對(duì)我來(lái)說(shuō)反正調(diào)用方式?jīng)]什么變化, 于是我將信將疑地像以前把4個(gè)參數(shù)傳遞過(guò)去, 他馬上就忙活起來(lái),建立連接,發(fā)送數(shù)據(jù),接收數(shù)據(jù),過(guò)了很久(我感覺(jué)比平時(shí)要慢了100倍)他才說(shuō)房貸已經(jīng)計(jì)算好了,數(shù)據(jù)在地址XXXX處, 你去拿吧。
我去那個(gè)地方一查,和往常一樣,每月的還款結(jié)果已經(jīng)整整齊齊的擺在那里了。
“你這個(gè)房貸計(jì)算的客戶端代理還真不含糊啊, 既然你是客戶端代理, 難道還有服務(wù)器端代理人? ”
“沒(méi)錯(cuò), 我還有個(gè)好基友,在服務(wù)器端忙活, 我和他約定好了消息的格式, 你交給我的數(shù)據(jù)其實(shí)我都通過(guò)socket發(fā)給他了,由他來(lái)調(diào)用真正的房貸計(jì)算, 然后再把結(jié)果發(fā)回來(lái)。”
“難道這就是傳說(shuō)中的遠(yuǎn)程過(guò)程調(diào)用(RPC) ? ” 我問(wèn)道
“是的, 我們這兩個(gè)代理人把臟活累活都幫著你們做了,把那些復(fù)雜的網(wǎng)絡(luò)細(xì)節(jié)都給隱藏起來(lái)了, 在你們看來(lái)和本地調(diào)用一樣。 對(duì)了,有人會(huì)把我稱為Stub, 把我的好基友稱為Skeleton, 我和他之間的交互是通過(guò)socket進(jìn)行的, 有些RPC的代理人可能不用這么底層的東西,直接用http, 不過(guò)沒(méi)關(guān)系,只要兩端的代理人約定好就行了, 關(guān)鍵是要給你們提供一個(gè)舒適的體驗(yàn)。”
“我想到一個(gè)問(wèn)題, 如果我傳遞給你的不是簡(jiǎn)單的float, int型的參數(shù), 而是內(nèi)存中的對(duì)象, 怎么處理?”
“當(dāng)然要做序列化了, 要不然怎么通過(guò)網(wǎng)絡(luò)發(fā)送啊, 其實(shí)float,int也得做序列化, 把內(nèi)存中的值和對(duì)象變成二進(jìn)制流,這樣才能發(fā)送出去。到了我的好基友那邊,他還得做反序列化,把而二進(jìn)制流再轉(zhuǎn)化為對(duì)象, 然后才能調(diào)用真正的函數(shù), 唉,這工作實(shí)在是麻煩啊。”
我對(duì)他表示了深切的同情和敬意, 為了我們能做透明的遠(yuǎn)程調(diào)用,這些代理們真不容易。
“我聽(tīng)說(shuō)還能用XML和JSON?” 我問(wèn)道
“你知道的不少嘛 ! 有些人在使用Http 作為通信協(xié)議的時(shí)候, 喜歡把對(duì)象變成文本,例如XML/JSON,可讀性比較好,但是你要知道,雖然應(yīng)用層的HTTP中看起來(lái)時(shí)文本, 但是到了底層通道例如TCP發(fā)送出去的時(shí)候,那還得變成二進(jìn)制流, 到了目的地再把他們轉(zhuǎn)化成文本。”
聊了半天,我們?cè)絹?lái)越熟, 我無(wú)意間談起了他的身世, 他說(shuō) : “我們這些代理人啊,出生的方式主要有兩種, 一種就是程序員們一行行代碼的把我們給敲出來(lái)、費(fèi)心而費(fèi)力, 另外一種就是自動(dòng)生成。”
“自動(dòng)生成,具體怎么做?”
“拿Java來(lái)舉個(gè)例子, 你可以先定義一個(gè)接口(interface), 讓這個(gè)接口擴(kuò)展自java.rmi.Remote, 然后寫(xiě)個(gè)實(shí)現(xiàn)類, 最后用一個(gè)工具rmic就可以自動(dòng)生成客戶端和服務(wù)器端的代理人了 , 是不是很簡(jiǎn)單? ”
(碼農(nóng)翻身老劉注: 從JDK5.0開(kāi)始, 連這個(gè)rmic這一步都可以省略, 完全由JVM自動(dòng)生成,運(yùn)行時(shí)可以把客戶端代理人下載到客戶端。)
網(wǎng)絡(luò)的世界遠(yuǎn)比單機(jī)精彩, 不知不覺(jué)我已經(jīng)和這個(gè)代理人聊了將近800毫秒, 我的上司已經(jīng)等不及了,他抱怨地說(shuō): “這次怎么這么慢? 難道人類在調(diào)試,在你這里加了斷點(diǎn)?”
我說(shuō) :“沒(méi)有調(diào)試, 原來(lái)是本地過(guò)程調(diào)用,現(xiàn)在變成遠(yuǎn)程過(guò)程調(diào)用了!”
【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)作者微信公眾號(hào)coderising獲取授權(quán)】