您的位置:软件测试 > 开源软件测试 > 开源单元测试工具 >
客户机应用程序的性能测试
作者:网络转载 发布时间:[ 2013/2/21 14:52:40 ] 推荐标签:

viewer.addSelectionChangedListener(new ISelectionChangedListener() {
    public void selectionChanged(SelectionChangedEvent event) {
        new Job("go to db") {
            protected IStatus run(IProgressMonitor monitor) {
                //do expensive work here
                return Status.OK_STATUS;
            }
        }.schedule();
    }
});


清单 3 的开发人员知道这个操作很耗时,把它放到一个后台 Job 中去做。但是问题在于开发人员没有预料到 用户可能在收件箱中选择一条消息后会按住键盘上的向下箭头持续几秒钟。 一般在这种情况下,每个选择的改变会导致执行一个新的后台 Job。很快,JobManager 会被 Job 填满。

清单 4 提供了一个更好的选择,不使用选择处理程序, 而是用 postSelection 处理程序。JFace 为执行事件接合 提供了 PostSelection 处理程序,从而使得后一个选择成为您的应用程序所接受的 选择 —— 而不是您的应用程序无法处理的一大堆选择。 您可以认为它忽略了过于嘈杂的细小事件,仅关注其中一些较大的。

清单 4. 仅对后一个选择改变做响应的选择侦听器

               
viewer.addPostSelectionChangedListener(new ISelectionChangedListener() {
    public void selectionChanged(SelectionChangedEvent event) {
        new Job("go to db") {
            protected IStatus run(IProgressMonitor monitor) {
                //do expensive work here
                return Status.OK_STATUS;
            }
        }.schedule();
    }
};

处理磁盘 I/O

您一定听说过:内存读写以纳秒计,磁盘读写以毫秒计。 在我曾参与的绝大多数 RCP 应用程序中,瓶颈是 CPU,而不是磁盘 I/O。 但是,磁盘 I/O 仍然可能成为问题,您不应忽视它。 RCP 应用程序的一类常见问题是对磁盘的低效率映象读取。

我一般使用 Sysinternals Process Monitor 考察一个应用程序如何使用文件。 举例而言,图 5 说明可以容易地识别对未缓冲文件的读取:

图 5. Process monitor 显示未缓冲读取 I/O

如果您逐行阅读图 5,您会发现正在读取一个名为 big.txt 的文件。 后一列说明对该文件每次只读取一个字节。清单 5 说明了导致这种情况的代码:

清单 5. 未缓冲的 I/O(不要这么做)

               
InputStream in = new FileInputStream(args[0]);
int c;
while ((c = in.read()) != -1) {
    //stuff characters in buffer, etc
}


我的 ThinkPad T60p 笔记本硬盘速度是 7200RPM,它读取一个 7MB 的文件需要 用 24 秒。如果用 BufferedInputStream,时间将减少到 350 毫秒。 绝大多数的此类提速可归功于更好地利用硬盘。可能您的绝大多数程序不会有这么巨大的效果, 但是仍然值得用象 BufferedInputStream 一样的缓冲流来解决未缓冲 I/O 问题。

我在 RCP 应用程序中观察到的另一个问题被我称为映象燃烧, 当从磁盘频繁读取一个映象然后丢弃时该问题会发生。根据频繁程度,该映象可能好进入缓存。

线程和 Eclipse 作业

应用程序应该充分利用计算机资源。 为了优化地使用 CPU,应用程序所拥有的线程数目应与处理程序计数和线程工作类型相关。 每个 Java 线程都关联着一定数量的本地内存,线程切换上下文时会导致一些 CPU 耗费, 所以并不是线程越多越好。

我经常在客户端应用程序中看到对线程的错误使用。对于那些曾可能阻塞 UI 线程的长时间运行操作, 用一些线程来做是好事,但是在基于 RCP 的应用程序中,Job(几乎)应该总优先于线程。
 

您还应小心不要让 JobManager 被 Job 填满, 因为这样的话,它的默认工作者池会无限增长下去。

Job 类似于 Runnable:它们描述 task,而不是所运行的线程。Job(并不令人惊讶)由 JobManager 管理,它维持着一个工作者池。即很多 Job 可以被一个工作者池管理。Job 相比于线程所具有的另一个大优势是 Job 可以从外部(out-of-the-box)进行记录。您可以设置一些标识并运行应用程序,JobManager 会告诉您每个 Job 何时被创建、安排、运行以及完成。JobManager 还会告诉您它是如何管理工作者池。 当您试图了解何时执行后台 Job 以及它们的运行需要多长时间时,这会是一个巨大的优势。

要启用这项支持,将 清单 6 的内容添加到一个文件。(此信息可以在org.eclipse.core.jobs 包的 .options 文件中找到。) 然后启动您的 RCP 应用程序,需要有 -debug Path_to_debug_file .

清单 6. 启用 Job 调试信息

               
# Prints debug information on running background jobs
org.eclipse.core.jobs/jobs=true
# Includes current date and time in job debug information
org.eclipse.core.jobs/jobs/timing=true
# Computes location of error on mismatched IJobManager.beginRule/endRule
org.eclipse.core.jobs/jobs/beginend=true
# Pedantic assertion checking on locks and deadlock reporting
org.eclipse.core.jobs/jobs/locks=true
# Throws an IllegalStateException when deadlock occurs
org.eclipse.core.jobs/jobs/errorondeadlock=true
# Debug shutdown behaviour
org.eclipse.core.jobs/jobs/shutdown=true


Job 还支持高级计划规则。 您可以创建简单的或复杂的计划规则,支配 Job 的运行时机。清单 7 说明了一种方式,您可以创建一条规则,禁止 两个 Job 同时运行:

清单 7. 禁止两个 Job 同时运行

               
ISchedulingRule onlyOne = new ISchedulingRule() {
    public boolean isConflicting(ISchedulingRule rule) {
        return rule == this;
    }
    public boolean contains(ISchedulingRule rule) {
        return rule == this;
    }
};
Job job1 = new LongRunningJob();
Job job2 = new LongRunningJob();
job1.setRule(onlyOne);
job2.setRule(onlyOne);
job1.schedule();
job2.schedule();
return onlyOne;


清单 7 中的代码能够工作,是因为计划规则的 isConflicting() 方法在 Job 运行前被调用。当 job1 执行时,它 “拥有” 该规则。请参阅 ISchedulingRule 的实现。要获得更多示例(请参阅 参考资料)。

java.util.Timer 也容易被错误使用。 很多应用程序会创建几个 Timer,每个 Timer 创建一个专门的管理线程。典型地,每个应用程序应只创建一个 Timer 并让它管理多个 java.util.TimerTask,但是很多相互孤立的开发人员会创建他们自己的 Timer,这只会浪费更多的线程。在几乎所有的 RCP 应用程序案例中,java.util.Timer 可以被 Job 取代,计划在未来某个时间执行。

如果您所运行的 JVM 版本高于 1.4,您能从 java.util.concurrent Executor、ScheduledThreadPoolExecutor 和 Task 得到大量相同好处。java.util.Timer 类并未受到轻视,但不管出于何种目的, 它都可由 ScheduledExecutorService替代。

上一页12345下一页
软件测试工具 | 联系我们 | 投诉建议 | 诚聘英才 | 申请使用列表 | 网站地图
沪ICP备07036474 2003-2017 版权所有 上海泽众软件科技有限公司 Shanghai ZeZhong Software Co.,Ltd