亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

為JAVA性能而設計(三)

發布時間:2020-08-13 21:46:54 來源:ITPUB博客 閱讀:121 作者:rainytag 欄目:編程語言

  第三部分: 遠程接口

  概述
  許多 Java 的通常性能問題來源于設計過程早期的類設計想法中, 早在開發者開始考慮性能問題之前. 在這個系列中, Brian Goetz 討論了一些通常的 Java 性能的冒險, 解釋了怎樣在設計時間避免它們. 在這篇文章中, 它檢驗了遠程應用程序中的特定的性能問題.

  遠程調用的概念

  在分布式的應用程序中, 一個運行在一個系統中的對象可以調用另一個系統中的一個對象的方法. 這個通過很多使遠程對象表現為本地的結構的幫助而實現. 要訪問一個遠程對象,你首先要找到它, 可以通過使用目錄或者命名服務來實現, 象 RMI 注冊, JNDI, 或者 CORBA命名服務.

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

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

  遠程和本地方法調用的性能比較

  遠程對象訪問的性能特征和本地的不一樣:遠程對象的創建比本地對象創建代價要高. 不僅僅是當它不存在時要創建它, 而且stub對和skeleton對象也要創建, 還要互相感知.

  遠程方法調用還包括網絡的傳遞 -- 匯集起來的參數必須發送到遠程系統, 而且響應也需匯集起來, 在調用程序重新得到控制權之前發送回來. 匯集, 分解, 網絡延時, 實際的遠調用所導致的延遲都加在一起; 客戶端通常是等待所有這些而步驟完成. 一個遠程調用也大地依賴于底層網絡的延時.

  不同的數據類型有不同的匯集開支. 匯集原類型相對來說花費少一些; 匯集簡單的對象, Point 或者 String 要多一些; 匯集遠程對象要多得多, 而匯集那些引用非常多的對象的對象(象 collection 等)要更多. 這和本地調用完全矛盾, 因為傳遞一個簡單對象的引用比一個復雜對象的引用花費多.

  接口設計是關鍵

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

  實際遠程應用程序的一些重要的性能指導:

  提防不必要的數據傳遞. 如果一個對象要同時得到幾個相關的項, 如果可能的話, 在一個遠程調用中實現可能容易一些.
  當調用者可能不必要保持一個遠程對象的引用時, 提防返回遠程的對象.當遠程對象不需要一個對象的拷貝時, 提防傳遞復雜對象.
  幸運的是, 你可以通過簡單查看遠程對象的接口來找出所有的問題. 要求做任何高層動作的方法調用序列可以從類接口中明顯看到. 如果你看到一個通常的高層操作需要許多連續的遠程方法調用, 這就是一個警告信號, 可能你需要重新查看一下類接口.

  減少遠程調用代價的技巧

  一個例子, 考慮下面假定的管理一個組織目錄的應用程序: 一個遠程的 Directory 對象包含了 DirectoryEntry 對象的引用, 表現了電話簿的入口.

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();
}

  現在假設你想在一個 GUI email 程序中使用 Directory 的東西. 程序首先調用getEntries() 來得到入口的列表, 接著在每個入口中調用 getName(), 計算結果的列表,當用戶選擇一個時, 應用程序在相應的入口調用 getEmailAdress() 來得到 email 地址.

  在你能夠寫一封 email 之前有多少遠程方法調用必須發生? 你必須調用 getEntries() 一次, 地址簿中每個入口調用一次 getName(), 一次 getEmailAddress(). 所以如果在地址中有 N 個入口, 你必須進行 N + 2 次遠程調用. 注意你也需要創建 N + 1 個遠程對象引用, 也是一個代價很高的操作. 如果你的地址簿有許多入口的話, 不僅僅是打開 email 窗口的時候非常慢, 也造成了網絡阻塞, 給你的目錄服務程序造成高負載, 導致可擴展性的問題.

  現在考慮增強的 Directory 接口:

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

  這將減少多少你的 email 程序所造成的花費呢? 現在你可以調用 Directory.getNames()一次就可以同時得到所有的名字, 只需要給你想要發送 email 的容器調用 getEntryByName() .這個過程需要 3 個遠程方法調用, 而不是 N + 2, 和兩個遠程對象, 而不是 N + 1 個.如果地址簿有再多一點的名字, 這個調用的減少在程序的響應和網絡負載和系統負載有很大的不同.

  用來減少遠程調用和引用傳遞的代價的技術叫做使用次要對象標識符. 使用一個對象的標屬性, -- 在這個例子中, 是 name -- 而不是傳回一個遠程對象, 作為對象的一個輕量級曄斗?次要標識符包含了它描述的對象足夠的信息, 這樣你只需要獲取你實際需要的遠程對象.在這個目錄系統的例子中, 一個人的名字是一個好的次要標識符. 在另一個例子中, 一個安全皮包管理系統, 一個采購標識號可能是一個好的次要標識符.

  另一個減少遠程調用數量的技巧是塊獲取. 你可以進一步給 Directory 接口加個方法, 來一次獲取多個需要的 DirectoryEntry 對象:

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);
}

  現在你不僅可以得到需要的遠程 DirectoryEntry , 也可以用單獨一個遠程方法調用得到要的所有的入口. 雖然這并不減少匯集的代價, 但極大地較少了網絡往返的次數. 如果網延遲很重要的話, 就可以產生一個響應更快的系統(也能減少這個網絡的使用).

  照亮去向 RMI 層次的路徑的第三的技巧是不把 DirectoryEntry 作為一個遠程對象, 而把它定義為一個通常的對象, 帶有訪問 name, address, email address 和其他域的訪問函數.(在 CORBA 系統中, 我可能要使用類似的 object-by-value 機制.) 然后, 當 email 應用程序調用 getEntryName() 時, 它會獲取一個 entry 對象的值 -- 不需要創建一個stub對象或者skeleton對象, getEmailAddress() 的調用也是一個本地的調用而不是一個遠程的.

  當然, 所有這些技巧都都依賴于對遠程對象實際上是怎樣使用的理解上的, 但是對于這個理解, 你甚至不需要看一看遠程類的實現就可以找出一些潛在的嚴重性能問題.

  結論

  分布式的應用程序的性能特性本質上和本地程序不同. 許多對于本地程序代價很小的操作對于遠程應用程序來說代價非常高, 設計不好的遠程接口導致一個程序有嚴重的擴展性和能問題.

  幸運的是, 很容易在設計時候, 為那些高代價的操作(象遠程調用和遠程對象創建), 通過平常的用例和分析它們, 確定和解決許多通常的分布式的性能問題, 正確使用這里提到的技巧,次要的對象標識符, 塊獲取和 return-by-value -- 可以本質上提高用戶響應時間和整個統的吞吐量.

[@more@]
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

万山特区| 乌兰浩特市| 富宁县| 金山区| 开封县| 宝兴县| 阿克苏市| 德江县| 论坛| 宽甸| 莫力| 井研县| 柞水县| 武威市| 海原县| 富宁县| 武宁县| 榆中县| 阳西县| 历史| 锦屏县| 辽阳市| 桐梓县| 黄石市| 水城县| 山丹县| 民勤县| 突泉县| 乐清市| 蕲春县| 东兴市| 彭州市| 宁河县| 张家口市| 如皋市| 绥芬河市| 定南县| 九江市| 青冈县| 静海县| 兴安县|