您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 >
客戶機應(yīng)用程序的性能測試
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時間:[ 2013/2/21 14:52:40 ] 推薦標(biāo)簽:

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 的開發(fā)人員知道這個操作很耗時,把它放到一個后臺 Job 中去做。但是問題在于開發(fā)人員沒有預(yù)料到 用戶可能在收件箱中選擇一條消息后會按住鍵盤上的向下箭頭持續(xù)幾秒鐘。 一般在這種情況下,每個選擇的改變會導(dǎo)致執(zhí)行一個新的后臺 Job。很快,JobManager 會被 Job 填滿。

清單 4 提供了一個更好的選擇,不使用選擇處理程序, 而是用 postSelection 處理程序。JFace 為執(zhí)行事件接合 提供了 PostSelection 處理程序,從而使得后一個選擇成為您的應(yīng)用程序所接受的 選擇 —— 而不是您的應(yīng)用程序無法處理的一大堆選擇。 您可以認為它忽略了過于嘈雜的細小事件,僅關(guān)注其中一些較大的。

清單 4. 僅對后一個選擇改變做響應(yīng)的選擇偵聽器

               
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

您一定聽說過:內(nèi)存讀寫以納秒計,磁盤讀寫以毫秒計。 在我曾參與的絕大多數(shù) RCP 應(yīng)用程序中,瓶頸是 CPU,而不是磁盤 I/O。 但是,磁盤 I/O 仍然可能成為問題,您不應(yīng)忽視它。 RCP 應(yīng)用程序的一類常見問題是對磁盤的低效率映象讀取。

我一般使用 Sysinternals Process Monitor 考察一個應(yīng)用程序如何使用文件。 舉例而言,圖 5 說明可以容易地識別對未緩沖文件的讀。

圖 5. Process monitor 顯示未緩沖讀取 I/O

如果您逐行閱讀圖 5,您會發(fā)現(xiàn)正在讀取一個名為 big.txt 的文件。 后一列說明對該文件每次只讀取一個字節(jié)。清單 5 說明了導(dǎo)致這種情況的代碼:

清單 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 毫秒。 絕大多數(shù)的此類提速可歸功于更好地利用硬盤?赡苣慕^大多數(shù)程序不會有這么巨大的效果, 但是仍然值得用象 BufferedInputStream 一樣的緩沖流來解決未緩沖 I/O 問題。

我在 RCP 應(yīng)用程序中觀察到的另一個問題被我稱為映象燃燒, 當(dāng)從磁盤頻繁讀取一個映象然后丟棄時該問題會發(fā)生。根據(jù)頻繁程度,該映象可能好進入緩存。

線程和 Eclipse 作業(yè)

應(yīng)用程序應(yīng)該充分利用計算機資源。 為了優(yōu)化地使用 CPU,應(yīng)用程序所擁有的線程數(shù)目應(yīng)與處理程序計數(shù)和線程工作類型相關(guān)。 每個 Java 線程都關(guān)聯(lián)著一定數(shù)量的本地內(nèi)存,線程切換上下文時會導(dǎo)致一些 CPU 耗費, 所以并不是線程越多越好。

我經(jīng)常在客戶端應(yīng)用程序中看到對線程的錯誤使用。對于那些曾可能阻塞 UI 線程的長時間運行操作, 用一些線程來做是好事,但是在基于 RCP 的應(yīng)用程序中,Job(幾乎)應(yīng)該總優(yōu)先于線程。
 

您還應(yīng)小心不要讓 JobManager 被 Job 填滿, 因為這樣的話,它的默認工作者池會無限增長下去。

Job 類似于 Runnable:它們描述 task,而不是所運行的線程。Job(并不令人驚訝)由 JobManager 管理,它維持著一個工作者池。即很多 Job 可以被一個工作者池管理。Job 相比于線程所具有的另一個大優(yōu)勢是 Job 可以從外部(out-of-the-box)進行記錄。您可以設(shè)置一些標(biāo)識并運行應(yīng)用程序,JobManager 會告訴您每個 Job 何時被創(chuàng)建、安排、運行以及完成。JobManager 還會告訴您它是如何管理工作者池。 當(dāng)您試圖了解何時執(zhí)行后臺 Job 以及它們的運行需要多長時間時,這會是一個巨大的優(yōu)勢。

要啟用這項支持,將 清單 6 的內(nèi)容添加到一個文件。(此信息可以在org.eclipse.core.jobs 包的 .options 文件中找到。) 然后啟動您的 RCP 應(yīng)用程序,需要有 -debug Path_to_debug_file .

清單 6. 啟用 Job 調(diào)試信息

               
# 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 還支持高級計劃規(guī)則。 您可以創(chuàng)建簡單的或復(fù)雜的計劃規(guī)則,支配 Job 的運行時機。清單 7 說明了一種方式,您可以創(chuàng)建一條規(guī)則,禁止 兩個 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 中的代碼能夠工作,是因為計劃規(guī)則的 isConflicting() 方法在 Job 運行前被調(diào)用。當(dāng) job1 執(zhí)行時,它 “擁有” 該規(guī)則。請參閱 ISchedulingRule 的實現(xiàn)。要獲得更多示例(請參閱 參考資料)。

java.util.Timer 也容易被錯誤使用。 很多應(yīng)用程序會創(chuàng)建幾個 Timer,每個 Timer 創(chuàng)建一個專門的管理線程。典型地,每個應(yīng)用程序應(yīng)只創(chuàng)建一個 Timer 并讓它管理多個 java.util.TimerTask,但是很多相互孤立的開發(fā)人員會創(chuàng)建他們自己的 Timer,這只會浪費更多的線程。在幾乎所有的 RCP 應(yīng)用程序案例中,java.util.Timer 可以被 Job 取代,計劃在未來某個時間執(zhí)行。

如果您所運行的 JVM 版本高于 1.4,您能從 java.util.concurrent Executor、ScheduledThreadPoolExecutor 和 Task 得到大量相同好處。java.util.Timer 類并未受到輕視,但不管出于何種目的, 它都可由 ScheduledExecutorService替代。

上一頁12345下一頁
軟件測試工具 | 聯(lián)系我們 | 投訴建議 | 誠聘英才 | 申請使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd