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

為了了解原因,您可以設(shè)想應(yīng)用程序上有一個(gè)按鈕,單擊按鈕時(shí)要做一些工作, 于是您對(duì)它添加了一個(gè)事件處理程序。 當(dāng)用戶單擊該按鈕時(shí),OS 調(diào)用 GUI 工具包,轉(zhuǎn)而調(diào)用 您定義的事件處理函數(shù)。事件的處理代碼現(xiàn)在運(yùn)行于 UI 線程, 而且只要這段代碼在運(yùn)行,UI 線程無法對(duì)其他 UI 事件作出響應(yīng)。 這意味著 UI 看上去凍結(jié)了,用戶將對(duì)此情況感到不安。 問題的重點(diǎn)在于如果 UI 線程在運(yùn)行您的代碼,應(yīng)用程序?qū)o法 再處理來自 OS 的 UI 事件。 如果應(yīng)用程序有一個(gè)按鈕用于取消某個(gè)長(zhǎng)時(shí)間運(yùn)行的操作,而您正在使用 UI 線程 執(zhí)行操作,那么這個(gè)取消事件只有到 UI 線程所做的操作完成后才會(huì)被處理! (如果代碼在 UI 線程中運(yùn)行過久,OS 會(huì)提醒用戶,為用戶提供選項(xiàng)以 終止該應(yīng)用程序。)

上述情形說明了為什么 UI 線程上的緩慢和無法預(yù)期的 I/O 會(huì)造成問題。 每種類型的 I/O 都可能擁有極為不同的特性。磁盤 I/O 一般遵從線形 模型反應(yīng)時(shí)間(latency)+ 傳輸速率 * 數(shù)據(jù)量。 另一方面,網(wǎng)絡(luò) I/O 則沒有這么規(guī)則。它不僅比磁盤 I/O 慢,而且在可靠性上也遠(yuǎn)不如磁盤 I/O, 這是因?yàn)樗鼤?huì)受到(可能是暫時(shí)性地)網(wǎng)絡(luò)端點(diǎn)間擁塞的影響。

由于在開發(fā)時(shí)網(wǎng)絡(luò)可能很快而且延遲很小,所以很容易忽視 網(wǎng)絡(luò) I/O 在 UI 線程上造成的影響。在開發(fā)環(huán)境下,容易無意識(shí)地在 UI 線程上 做網(wǎng)絡(luò)調(diào)用,直到在較慢或穩(wěn)定性較差的網(wǎng)絡(luò)上運(yùn)行的用戶注意到每次進(jìn)入網(wǎng)絡(luò) UI 線程都會(huì)凍結(jié)時(shí),才發(fā)現(xiàn)這個(gè)問題。 再加上套接字超時(shí),應(yīng)用程序如果五秒鐘內(nèi)沒有響應(yīng) UI 事件,則 Windows 經(jīng)常出現(xiàn) “死亡白屏” 的情況。

表 1 介紹了一些用于發(fā)現(xiàn) UI 線程上長(zhǎng)時(shí)間運(yùn)行的操作的技術(shù),以及它們的優(yōu)缺點(diǎn):

 

技術(shù) 優(yōu)點(diǎn) 缺點(diǎn)
使用分析器 如果您有一個(gè)分析器,那么設(shè)置它并不麻煩。 一般要花錢。
耗費(fèi)的運(yùn)行時(shí)間可能非常高。
記錄 JDK 設(shè)置好后可以和應(yīng)用程序很好地合作,直到升級(jí)該 JDK。
耗費(fèi)的運(yùn)行時(shí)間很少。
不容易和他人共享。
記錄代碼 很多用戶可以共享,因?yàn)閱⒂糜涗浐,客戶、QA、開發(fā)人員和其他人都能運(yùn)行。 可能要求您改變應(yīng)用程序的架構(gòu)以發(fā)現(xiàn)所有做了網(wǎng)絡(luò)調(diào)用的位置。
必須注意不要添加未被記錄的新方法。
需要記錄處理日志,日志文件會(huì)變得很大。

記錄技術(shù)

您可以用很多技術(shù)來洞察應(yīng)用程序所做的事情。 本節(jié)介紹其中一些技術(shù)。

使用方面(aspect)

您可以用面向方面(aspect-oriented)技術(shù)將變化 “編織” 到被記錄的類中。 舉例而言,可以直接將代碼組合到 SocketInputStream 和 SocketOutputStream 檢查流是否被 UI 線程訪問 (請(qǐng)參閱 參考資料 上關(guān)于面向方面技術(shù)和工具的更多信息的鏈接。)
 
Swing 與 SWT 的對(duì)比

Swing 和 SWT 的不同之處在于對(duì) UI 線程的命名方式。在 SWT 中,UI 線程往往 命名為 main。在 Swing 中,您使用 java.awt.EventQueue.isDispatchThread() 詢問 當(dāng)前線程是否是分發(fā)線程。本文后面的例子按照 SWT 方法;如果您用的是 Swing,做對(duì)應(yīng)的替換即可。

使用斷點(diǎn)

如果能在調(diào)試器里運(yùn)行您的應(yīng)用程序,有些時(shí)候用條件斷點(diǎn)記錄 JDK 更加簡(jiǎn)單。 我曾參與過一個(gè)大型應(yīng)用程序,它在 UI 線程上進(jìn)行網(wǎng)絡(luò)調(diào)用。該應(yīng)用程序的結(jié)構(gòu) (大量第三方代碼)使得分辨誰來負(fù)責(zé)網(wǎng)絡(luò)調(diào)用很困難,而在 Eclipse 中的 SocketInputStream 類設(shè)置條件斷點(diǎn)(如 圖 4 所示), 則很容易分辨出來:

圖 4. 條件斷點(diǎn)

使用安全管理器

另外,我曾成功地使用一個(gè)記錄式安全管理器替換應(yīng)用程序的安全管理器。 大量有趣的調(diào)用通過安全管理器傳遞。 比如,清單 1 中的安全管理器 記錄了一條消息,它試圖在 UI 線程中打開一個(gè)套接字:

清單 1. 記錄在 UI 線程中打開套接字時(shí)的錯(cuò)誤

               
SecurityManager securityManager = new SecurityManager() {
    public void checkPermission(Permission perm) {
        if(perm instanceof java.net.SocketPermission) {
            if(Thread.currentThread().getName().equals("main&")) {
                logger.log(Level.SEVERE, "Network call on UI thread&");
                new Error().printStackTrace();
            }
        }
    }
};
System.setSecurityManager(securityManager);


記錄代碼

如果您的應(yīng)用程序分層很好,網(wǎng)絡(luò)調(diào)用只經(jīng)過一個(gè)(或很少)位置, 則能夠在進(jìn)行網(wǎng)絡(luò)調(diào)用之前用應(yīng)用程序代碼檢查當(dāng)前線程, 如 清單 2 中所示。 在構(gòu)建產(chǎn)品時(shí)我會(huì)保留此類代碼,因?yàn)榫程檢查很開銷較低。 創(chuàng)建并記錄異常日志會(huì)導(dǎo)致一些時(shí)間開銷,但是堆棧跟蹤可以很好地用于 捕獲問題原因。

清單 2. 記錄在 UI 線程中做網(wǎng)絡(luò)調(diào)用時(shí)的錯(cuò)誤

               
if(Thread.currentThread().getName().equals("main")) {
    logger.log(Level.SEVERE, "Network call on UI thread");
    new Error().printStackTrace();
}


修改 JDK 的類

作為后一種手段,您可以通過修改 JDK 的類達(dá)到記錄 JDK 的目的。 這種手段不受支持、復(fù)雜并且有黑客嫌疑 —— 而且可能侵犯許可 —— 但是對(duì)于 某些不常見的情形,當(dāng)前述技術(shù)無能為力時(shí),它還是一個(gè)有價(jià)值的選擇。 這種技術(shù)的要點(diǎn)是重新編譯 JDK 的類,并使用 -Xbootclasspath/p: 預(yù)置 JAR 或目錄到您的啟動(dòng)類路徑中。

避免 UI 線程中的長(zhǎng)時(shí)間運(yùn)行動(dòng)作

有一些技術(shù)用來避免 UI 線程中的長(zhǎng)時(shí)間運(yùn)行動(dòng)作, 舉一個(gè)常見的例子:使用某種數(shù)據(jù)庫查詢、網(wǎng)絡(luò)調(diào)用或磁盤進(jìn)行填充的表或樹。

不要指望您能在 UI 線程中填充該表。 也許可以處理幾百個(gè)項(xiàng)目,但是上千個(gè)項(xiàng)目則處理不了。

更好

不要指望在顯示給用戶初始結(jié)果之前完全填充該表或樹。舉例而言, 如果您正在開發(fā)一個(gè)電子郵件客戶機(jī),您定不希望先載入所有文件夾下的所有郵件消息并生成表, 然后再給用戶顯示一個(gè)滿是郵件消息的 “頁面”。

還有更好

充分利用 SWT/JFace 的虛擬部件。您可以使用幾種不同的技術(shù), 但是所有技術(shù)都?xì)w結(jié)于 “盡可能地延遲工作。” 在 UI 線程里,用占位符填充樹或表,在后臺(tái)的 Job 中, 檢索真實(shí)數(shù)據(jù)并在獲得數(shù)據(jù)后更新樹。

注意您在事件處理程序中做了多少工作。特別是注意捆綁到表、樹和列表的 SWT 選擇處理程序。 我看到過很多有此類錯(cuò)誤的代碼。比如,清單 3 中是來自一個(gè) 郵件應(yīng)用程序的選擇偵聽器;每當(dāng)選中一條消息,執(zhí)行一個(gè)數(shù)據(jù)庫查詢以讀取郵件詳情并用它更新 UI:

清單 3. 對(duì)每個(gè)選擇改變做響應(yīng)的選擇偵聽器

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