真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

為JAVA性能而設(shè)計(jì)(三)

  第三部分: 遠(yuǎn)程接口

創(chuàng)新互聯(lián)是一家專業(yè)提供圖木舒克企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、H5頁面制作、小程序制作等業(yè)務(wù)。10年已為圖木舒克眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進(jìn)行中。

  概述
  許多 Java 的通常性能問題來源于設(shè)計(jì)過程早期的類設(shè)計(jì)想法中, 早在開發(fā)者開始考慮性能問題之前. 在這個(gè)系列中, Brian Goetz 討論了一些通常的 Java 性能的冒險(xiǎn), 解釋了怎樣在設(shè)計(jì)時(shí)間避免它們. 在這篇文章中, 它檢驗(yàn)了遠(yuǎn)程應(yīng)用程序中的特定的性能問題.

  遠(yuǎn)程調(diào)用的概念

  在分布式的應(yīng)用程序中, 一個(gè)運(yùn)行在一個(gè)系統(tǒng)中的對(duì)象可以調(diào)用另一個(gè)系統(tǒng)中的一個(gè)對(duì)象的方法. 這個(gè)通過很多使遠(yuǎn)程對(duì)象表現(xiàn)為本地的結(jié)構(gòu)的幫助而實(shí)現(xiàn). 要訪問一個(gè)遠(yuǎn)程對(duì)象,你首先要找到它, 可以通過使用目錄或者命名服務(wù)來實(shí)現(xiàn), 象 RMI 注冊(cè), JNDI, 或者 CORBA命名服務(wù).

  當(dāng)你通過目錄服務(wù)得到一個(gè)遠(yuǎn)程對(duì)象的引用時(shí), 你并沒有得到那個(gè)對(duì)象的實(shí)際的引用, 而是一個(gè)實(shí)現(xiàn)了和遠(yuǎn)程對(duì)象同樣接口的stub對(duì)象的引用. 當(dāng)你調(diào)用一個(gè)stub對(duì)象的方法時(shí), 對(duì)象把方法的所有參數(shù)匯集起來 -- 把它們轉(zhuǎn)化成一個(gè)字節(jié)流的表現(xiàn)形式, 類似于序列化過程. 這個(gè)stub對(duì)象把匯集的參數(shù)通過網(wǎng)絡(luò)傳遞給一個(gè)skeleton對(duì)象, 把參數(shù)分解出來, 你想調(diào)用的實(shí)際的對(duì)象的方法. 然后這個(gè)方法向skeleton對(duì)象返回一個(gè)值, skeleton對(duì)象把它傳送給stub對(duì)象, stub對(duì)象把它分解出來, 傳遞給調(diào)用者. Phew! 一個(gè)單獨(dú)的調(diào)用要做這么多的工作. 很明顯, 除去表面的相似性, 一個(gè)遠(yuǎn)程方法調(diào)用比本地方法調(diào)用更大.

  以上描述瀏覽了一些對(duì)于程序性能非常重要的細(xì)節(jié). 當(dāng)一個(gè)遠(yuǎn)程方法返回的不是一個(gè)原類? 而是一個(gè)對(duì)象時(shí), 會(huì)發(fā)生什么? 不一定. 如果返回的對(duì)象是一種支持遠(yuǎn)程方法調(diào)用的類型, 它就創(chuàng)建一個(gè)中stub對(duì)象和一個(gè)skeleton對(duì)象, 在這種情況下需要在注冊(cè)表中查找一個(gè)遠(yuǎn)潭韻,這顯然是一個(gè)高代價(jià)的操作. (遠(yuǎn)程對(duì)象支持一種分布式的垃圾回收的形式, 包括了每一個(gè)參與的 JVM 維護(hù)一個(gè)線程來和其他 JVM 的維護(hù)線程進(jìn)行通訊, 來回傳遞引用信息). 如果返回的對(duì)象不支持遠(yuǎn)程調(diào)用, 這個(gè)對(duì)象所有的域和引用的對(duì)象都要匯集起來, 這也是一個(gè)代價(jià)的操作.

  遠(yuǎn)程和本地方法調(diào)用的性能比較

  遠(yuǎn)程對(duì)象訪問的性能特征和本地的不一樣:遠(yuǎn)程對(duì)象的創(chuàng)建比本地對(duì)象創(chuàng)建代價(jià)要高. 不僅僅是當(dāng)它不存在時(shí)要?jiǎng)?chuàng)建它, 而且stub對(duì)和skeleton對(duì)象也要?jiǎng)?chuàng)建, 還要互相感知.

  遠(yuǎn)程方法調(diào)用還包括網(wǎng)絡(luò)的傳遞 -- 匯集起來的參數(shù)必須發(fā)送到遠(yuǎn)程系統(tǒng), 而且響應(yīng)也需匯集起來, 在調(diào)用程序重新得到控制權(quán)之前發(fā)送回來. 匯集, 分解, 網(wǎng)絡(luò)延時(shí), 實(shí)際的遠(yuǎn)調(diào)用所導(dǎo)致的延遲都加在一起; 客戶端通常是等待所有這些而步驟完成. 一個(gè)遠(yuǎn)程調(diào)用也大地依賴于底層網(wǎng)絡(luò)的延時(shí).

  不同的數(shù)據(jù)類型有不同的匯集開支. 匯集原類型相對(duì)來說花費(fèi)少一些; 匯集簡(jiǎn)單的對(duì)象, Point 或者 String 要多一些; 匯集遠(yuǎn)程對(duì)象要多得多, 而匯集那些引用非常多的對(duì)象的對(duì)象(象 collection 等)要更多. 這和本地調(diào)用完全矛盾, 因?yàn)閭鬟f一個(gè)簡(jiǎn)單對(duì)象的引用比一個(gè)復(fù)雜對(duì)象的引用花費(fèi)多.

  接口設(shè)計(jì)是關(guān)鍵

  設(shè)計(jì)不好的遠(yuǎn)程接口可能完全消除一個(gè)程序的性能. 不幸的是, 對(duì)本地對(duì)象來說好的接口的特性對(duì)遠(yuǎn)程對(duì)象可能不適合. 大量的臨時(shí)對(duì)象創(chuàng)建, 就象在本系列的第一, 二部分討論,也能阻礙分布式的應(yīng)用程序, 但是大量的傳遞更是一個(gè)性能問題. 所以, 調(diào)用一個(gè)在一個(gè)時(shí)對(duì)象(比如一個(gè) Point)中返回多個(gè)值的方法比多次調(diào)用來分別得到它們可能更有效.

  實(shí)際遠(yuǎn)程應(yīng)用程序的一些重要的性能指導(dǎo):

  提防不必要的數(shù)據(jù)傳遞. 如果一個(gè)對(duì)象要同時(shí)得到幾個(gè)相關(guān)的項(xiàng), 如果可能的話, 在一個(gè)遠(yuǎn)程調(diào)用中實(shí)現(xiàn)可能容易一些.
  當(dāng)調(diào)用者可能不必要保持一個(gè)遠(yuǎn)程對(duì)象的引用時(shí), 提防返回遠(yuǎn)程的對(duì)象.當(dāng)遠(yuǎn)程對(duì)象不需要一個(gè)對(duì)象的拷貝時(shí), 提防傳遞復(fù)雜對(duì)象.
  幸運(yùn)的是, 你可以通過簡(jiǎn)單查看遠(yuǎn)程對(duì)象的接口來找出所有的問題. 要求做任何高層動(dòng)作的方法調(diào)用序列可以從類接口中明顯看到. 如果你看到一個(gè)通常的高層操作需要許多連續(xù)的遠(yuǎn)程方法調(diào)用, 這就是一個(gè)警告信號(hào), 可能你需要重新查看一下類接口.

  減少遠(yuǎn)程調(diào)用代價(jià)的技巧

  一個(gè)例子, 考慮下面假定的管理一個(gè)組織目錄的應(yīng)用程序: 一個(gè)遠(yuǎn)程的 Directory 對(duì)象包含了 DirectoryEntry 對(duì)象的引用, 表現(xiàn)了電話簿的入口.

public interface Directory extends Remote {
DirectoryEntry[] getEntries();
void addEntry(DirectoryEntry entry);
void removeEntry(DirectoryEntry entry);
}
public interface DirectoryEntry extends Remote {
String getName();
String getPhoneNumber();
String getEmailAddress();
}

  現(xiàn)在假設(shè)你想在一個(gè) GUI email 程序中使用 Directory 的東西. 程序首先調(diào)用getEntries() 來得到入口的列表, 接著在每個(gè)入口中調(diào)用 getName(), 計(jì)算結(jié)果的列表,當(dāng)用戶選擇一個(gè)時(shí), 應(yīng)用程序在相應(yīng)的入口調(diào)用 getEmailAdress() 來得到 email 地址.

  在你能夠?qū)懸环?email 之前有多少遠(yuǎn)程方法調(diào)用必須發(fā)生? 你必須調(diào)用 getEntries() 一次, 地址簿中每個(gè)入口調(diào)用一次 getName(), 一次 getEmailAddress(). 所以如果在地址中有 N 個(gè)入口, 你必須進(jìn)行 N + 2 次遠(yuǎn)程調(diào)用. 注意你也需要?jiǎng)?chuàng)建 N + 1 個(gè)遠(yuǎn)程對(duì)象引用, 也是一個(gè)代價(jià)很高的操作. 如果你的地址簿有許多入口的話, 不僅僅是打開 email 窗口的時(shí)候非常慢, 也造成了網(wǎng)絡(luò)阻塞, 給你的目錄服務(wù)程序造成高負(fù)載, 導(dǎo)致可擴(kuò)展性的問題.

  現(xiàn)在考慮增強(qiáng)的 Directory 接口:

public interface Directory extends Remote {
String[] getNames();
DirectoryEntry[] getEntries();
DirectoryEntry getEntryByName(String name);
void addEntry(DirectoryEntry entry);
void removeEntry(DirectoryEntry entry);
}

  這將減少多少你的 email 程序所造成的花費(fèi)呢? 現(xiàn)在你可以調(diào)用 Directory.getNames()一次就可以同時(shí)得到所有的名字, 只需要給你想要發(fā)送 email 的容器調(diào)用 getEntryByName() .這個(gè)過程需要 3 個(gè)遠(yuǎn)程方法調(diào)用, 而不是 N + 2, 和兩個(gè)遠(yuǎn)程對(duì)象, 而不是 N + 1 個(gè).如果地址簿有再多一點(diǎn)的名字, 這個(gè)調(diào)用的減少在程序的響應(yīng)和網(wǎng)絡(luò)負(fù)載和系統(tǒng)負(fù)載有很大的不同.

  用來減少遠(yuǎn)程調(diào)用和引用傳遞的代價(jià)的技術(shù)叫做使用次要對(duì)象標(biāo)識(shí)符. 使用一個(gè)對(duì)象的標(biāo)屬性, -- 在這個(gè)例子中, 是 name -- 而不是傳回一個(gè)遠(yuǎn)程對(duì)象, 作為對(duì)象的一個(gè)輕量級(jí)曄斗?次要標(biāo)識(shí)符包含了它描述的對(duì)象足夠的信息, 這樣你只需要獲取你實(shí)際需要的遠(yuǎn)程對(duì)象.在這個(gè)目錄系統(tǒng)的例子中, 一個(gè)人的名字是一個(gè)好的次要標(biāo)識(shí)符. 在另一個(gè)例子中, 一個(gè)安全皮包管理系統(tǒng), 一個(gè)采購標(biāo)識(shí)號(hào)可能是一個(gè)好的次要標(biāo)識(shí)符.

  另一個(gè)減少遠(yuǎn)程調(diào)用數(shù)量的技巧是塊獲取. 你可以進(jìn)一步給 Directory 接口加個(gè)方法, 來一次獲取多個(gè)需要的 DirectoryEntry 對(duì)象:

public interface Directory extends Remote {
String[] getNames();
DirectoryEntry[] getEntries();
DirectoryEntry getEntryByName(String name);
DirectoryEntry[] getEntriesByName(String names[]);
void addEntry(DirectoryEntry entry);
void removeEntry(DirectoryEntry entry);
}

  現(xiàn)在你不僅可以得到需要的遠(yuǎn)程 DirectoryEntry , 也可以用單獨(dú)一個(gè)遠(yuǎn)程方法調(diào)用得到要的所有的入口. 雖然這并不減少匯集的代價(jià), 但極大地較少了網(wǎng)絡(luò)往返的次數(shù). 如果網(wǎng)延遲很重要的話, 就可以產(chǎn)生一個(gè)響應(yīng)更快的系統(tǒng)(也能減少這個(gè)網(wǎng)絡(luò)的使用).

  照亮去向 RMI 層次的路徑的第三的技巧是不把 DirectoryEntry 作為一個(gè)遠(yuǎn)程對(duì)象, 而把它定義為一個(gè)通常的對(duì)象, 帶有訪問 name, address, email address 和其他域的訪問函數(shù).(在 CORBA 系統(tǒng)中, 我可能要使用類似的 object-by-value 機(jī)制.) 然后, 當(dāng) email 應(yīng)用程序調(diào)用 getEntryName() 時(shí), 它會(huì)獲取一個(gè) entry 對(duì)象的值 -- 不需要?jiǎng)?chuàng)建一個(gè)stub對(duì)象或者skeleton對(duì)象, getEmailAddress() 的調(diào)用也是一個(gè)本地的調(diào)用而不是一個(gè)遠(yuǎn)程的.

  當(dāng)然, 所有這些技巧都都依賴于對(duì)遠(yuǎn)程對(duì)象實(shí)際上是怎樣使用的理解上的, 但是對(duì)于這個(gè)理解, 你甚至不需要看一看遠(yuǎn)程類的實(shí)現(xiàn)就可以找出一些潛在的嚴(yán)重性能問題.

  結(jié)論

  分布式的應(yīng)用程序的性能特性本質(zhì)上和本地程序不同. 許多對(duì)于本地程序代價(jià)很小的操作對(duì)于遠(yuǎn)程應(yīng)用程序來說代價(jià)非常高, 設(shè)計(jì)不好的遠(yuǎn)程接口導(dǎo)致一個(gè)程序有嚴(yán)重的擴(kuò)展性和能問題.

  幸運(yùn)的是, 很容易在設(shè)計(jì)時(shí)候, 為那些高代價(jià)的操作(象遠(yuǎn)程調(diào)用和遠(yuǎn)程對(duì)象創(chuàng)建), 通過平常的用例和分析它們, 確定和解決許多通常的分布式的性能問題, 正確使用這里提到的技巧,次要的對(duì)象標(biāo)識(shí)符, 塊獲取和 return-by-value -- 可以本質(zhì)上提高用戶響應(yīng)時(shí)間和整個(gè)統(tǒng)的吞吐量.

[@more@]
文章名稱:為JAVA性能而設(shè)計(jì)(三)
URL地址:http://weahome.cn/article/jdecje.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部