分享
 
 
 

为JAVA性能而设计(3)

王朝java/jsp·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

作者:eclipse

为性能而设计, 第三部分: 远程接口[/b]

学习怎样在设计 Java 类的时候避免性能冒险.

概述

许多 Java 的通常性能问题来源于设计过程早期的类设计想法中, 早在开发者开始考虑

性能问题之前. 在这个系列中, Brian Goetz 讨论了一些通常的 Java 性能的冒险, 解

释了怎样在设计时间避免它们. 在这篇文章中, 它检验了远程应用程序中的特定的性能

问题.

By Brian Goetz

翻译 by SuperMMX

这个系列探索一些早期的设计思想对应用程序的性能产生影响的方法. 第一部分, 检查了

一个类的对象创建行为是如何嵌入它的接口中的. 特定的接口实际上要求一个类创建临时

对象, 或者需要它的调用者来创建临时对象, 才能使用这个类. 因为临时对象的创建对 Java

程序来说是一个性能指标, 当你在设计时候, 能再对你的类接口做一些回顾来检查性能冒?

这是值得的.

在第一和第二部分我集中于对象的创建, 因为对许多 Java 程序来说这是一个很大的性能侍?

但是, 在分布式的应用程序中, 象建立在 RMI, CORBA, 或者 COM 之上的程序, 一个完全煌

的性能问题就在眼前了. 这篇文章探索一些针对远程程序的性能问题, 演示你怎样才能通

单地检查一个类的接口来猜测到分布式应用程序中的性能问题.

阅读这个 "为性能而设计" 系列:

第一部分: 接口事宜

第二部分: 减少对象创建

第三部分: 远程接口

远程调用的概观

在分布式的应用程序中, 一个运行在一个系统中的对象可以调用另一个系统中的一个对象

的方法. 这个通过很多使远程对象表现为本地的结构的帮助而实现. 要访问一个远程对象,

你首先要找到它, 可以通过使用目录或者命名服务来实现, 象 RMI 注册, JNDI, 或者 CORBA

命名服务.

当你通过目录服务得到一个远程对象的引用时, 你并没有得到那个对象的实际的引用, 而

是一个实现了和远程对象同样接口的stub对象的引用. 当你调用一个stub对象的方法时, 飧

对象把方法的所有参数汇集起来 -- 把它们转化成一个字节流的表现形式, 类似于序列化

过程. 这个stub对象把汇集的参数通过网络传递给一个skeleton对象, 把参数分解出来, 饔

你想调用的实际的对象的方法. 然后这个方法向skeleton对象返回一个值, skeleton对象逊祷刂祷慵

起来, 把它传送给stub对象, stub对象把它分解出来, 传递给调用者. Phew! 一个单独的椒

调用要做这么多的工作. 很明显, 除去表面的相似性, 一个远程方法调用比本地方法调用

更大.

以上描述浏览了一些对于程序性能非常重要的细节. 当一个远程方法返回的不是一个原类?

而是一个对象时, 会发生什么? 不一定. 假如返回的对象是一种支持远程方法调用的类型,

它就创建一个中stub对象和一个skeleton对象, 在这种情况下需要在注册表中查找一个远潭韵?

这显然是一个高代价的操作. (远程对象支持一种分布式的垃圾回收的形式, 包括了每一个

参与的 JVM 维护一个线程来和其他 JVM 的维护线程进行通讯, 往返传递引用信息). 假如

返回的对象不支持远程调用, 这个对象所有的域和引用的对象都要汇集起来, 这也是一个

代价的操作.

远程和本地方法调用的性能比较

远程对象访问的性能特征和本地的不一样:

远程对象的创建比本地对象创建代价要高. 不仅仅是当它不存在时要创建它, 而且stub对

和skeleton对象也要创建, 还要互相感知.

远程方法调用还包括网络的传递 -- 汇集起来的参数必须发送到远程系统, 而且响应也需

汇集起来, 在调用程序重新得到控制权之前发送回来. 汇集, 分解, 网络延时, 实际的远

调用所导致的延迟都加在一起; 客户端通常是等待所有这些而步骤完成. 一个远程调用也

大地依靠于底层网络的延时.

不同的数据类型有不同的汇集开支. 汇集原类型相对来说花费少一些; 汇集简单的对象,

Point 或者 String 要多一些; 汇集远程对象要多得多, 而汇集那些引用非常多的对象的

对象(象 collection 等)要更多. 这和本地调用完全矛盾, 因为传递一个简单对象的引用槐

一个复杂对象的引用花费多.

接口设计是要害

设计不好的远程接口可能完全消除一个程序的性能. 不幸的是, 对本地对象来说好的接口

的特性对远程对象可能不适合. 大量的临时对象创建, 就象在本系列的第一, 二部分讨论?

也能阻碍分布式的应用程序, 但是大量的传递更是一个性能问题. 所以, 调用一个在一个

时对象(比如一个 Point)中返回多个值的方法比多次调用来分别得到它们可能更有效. (注

意, 这和在第二部分给本地对象岢龅慕ㄒ?I 完全相反.)

实际远程应用程序的一些重要的性能指导:

提防不必要的数据传递. 假如一个对象要同时得到几个相关的项, 假如可能的话, 在一个

远程调用中实现可能轻易一些.

当调用者可能不必要保持一个远程对象的引用时, 提防返回远程的对象.

当远程对象不需要一个对象的拷贝时, 提防传递复杂对象.

幸运的是, 你可以通过简单查看远程对象的接口来找出所有的问题. 要求做任何高层动作

的方法调用序列可以从类接口中明显看到. 假如你看到一个通常的高层操作需要许多连续

的远程方法调用, 这就是一个警告信号, 可能你需要重新查看一下类接口.

减少远程调用代价的技巧

一个例子, 考虑下面假定的治理一个组织目录的应用程序: 一个远程的 Directory 对象包

含了 DirectoryEntry 对象的引用, 表现了电话簿的入口.

[code]

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

}

[/code]

现在假设你想在一个 GUI email 程序中使用 Directory 的东西. 程序首先调用

getEntries() 来得到入口的列表, 接着在每个入口中调用 getName(), 计算结果的列表,

当用户选择一个时, 应用程序在相应的入口调用 getEmailAdress() 来得到 email 地址.

在你能够写一封 email 之前有多少远程方法调用必须发生? 你必须调用 getEntries() 一

次, 地址簿中每个入口调用一次 getName(), 一次 getEmailAddress(). 所以假如在地址

中有 N 个入口, 你必须进行 N + 2 次远程调用. 注重你也需要创建 N + 1 个远程对象引

用, 也是一个代价很高的操作. 假如你的地址簿有许多入口的话, 不仅仅是打开 email 窗

口的时候非常慢, 也造成了网络阻塞, 给你的目录服务程序造成高负载, 导致可扩展性的

问题.

现在考虑增强的 Directory 接口:

[code]

public interface Directory extends Remote {

String[] getNames();

DirectoryEntry[] getEntries();

DirectoryEntry getEntryByName(String name);

void addEntry(DirectoryEntry entry);

void removeEntry(DirectoryEntry entry);

}

[/code]

这将减少多少你的 email 程序所造成的花费呢? 现在你可以调用 Directory.getNames()

一次就可以同时得到所有的名字, 只需要给你想要发送 email 的容器调用 getEntryByName() .

这个过程需要 3 个远程方法调用, 而不是 N + 2, 和两个远程对象, 而不是 N + 1 个.

假如地址簿有再多一点的名字, 这个调用的减少在程序的响应和网络负载和系统负载有很

大的不同.

用来减少远程调用和引用传递的代价的技术叫做使用次要对象标识符. 使用一个对象的标

属性, -- 在这个例子中, 是 name -- 而不是传回一个远程对象, 作为对象的一个轻量级晔斗?

次要标识符包含了它描述的对象足够的信息, 这样你只需要获取你实际需要的远程对象.

在这个目录系统的例子中, 一个人的名字是一个好的次要标识符. 在另一个例子中, 一个

安全皮包治理系统, 一个采购标识号可能是一个好的次要标识符.

另一个减少远程调用数量的技巧是块获取. 你可以进一步给 Directory 接口加个方法, 来一

次获取多个需要的 DirectoryEntry 对象:

[code]

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

}

[/code]

现在你不仅可以得到需要的远程 DirectoryEntry , 也可以用单独一个远程方法调用得到

要的所有的入口. 虽然这并不减少汇集的代价, 但极大地较少了网络往返的次数. 假如网

延迟很重要的话, 就可以产生一个响应更快的系统(也能减少这个网络的

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有