<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    鷹翔宇空

    學(xué)習(xí)和生活

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      110 Posts :: 141 Stories :: 315 Comments :: 1 Trackbacks
    原文引自:http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/SCArchDeGuide/Chapter1Introduction.mspx

    第 8 章 — 智能客戶端應(yīng)用程序性能

    發(fā)布日期: 08/20/2004 | 更新日期: 08/20/2004
    pponline

    智能客戶端體系結(jié)構(gòu)與設(shè)計(jì)指南

    David Hill、Brenton Webster、Edward A. Jezierski、Srinath Vasireddy、Mohammad Al-Sabt,Microsoft Corporation,Blaine Wastell Ascentium Corporation,Jonathan Rasmusson 和 Paul Gale ThoughtWorks 和 Paul Slater Wadeware LLC

    相關(guān)鏈接

    Microsoft? patterns & practiceshttp://www.microsoft.com/resources/practices/default.mspx

    .NET 的應(yīng)用程序體系結(jié)構(gòu):設(shè)計(jì)應(yīng)用程序和服務(wù)http://msdn.microsoft.com/library/en-us/dnbda/html/distapp.asp

    摘要:本章討論如何優(yōu)化您的智能客戶端應(yīng)用程序。本章分析您可以在設(shè)計(jì)時(shí)采取的步驟,并介紹如何調(diào)整智能客戶端應(yīng)用程序以及診斷任何性能問題。

    *
    本頁內(nèi)容
    針對性能進(jìn)行設(shè)計(jì) 針對性能進(jìn)行設(shè)計(jì)
    性能調(diào)整和診斷 性能調(diào)整和診斷
    小結(jié) 小結(jié)
    參考資料 參考資料

    智能客戶端應(yīng)用程序可以提供比 Web 應(yīng)用程序更豐富和響應(yīng)速度更快的用戶界面,并且可以利用本地系統(tǒng)資源。如果應(yīng)用程序的大部分駐留在用戶的計(jì)算機(jī)上,則應(yīng)用程序不需要到 Web 服務(wù)器的持續(xù)的往返行程。這有利于提高性能和響應(yīng)性。然而,要實(shí)現(xiàn)智能客戶端應(yīng)用程序的全部潛能,您應(yīng)該在應(yīng)用程序的設(shè)計(jì)階段仔細(xì)考慮性能問題。通過在規(guī)劃和設(shè)計(jì)您的應(yīng)用程序時(shí)解決性能問題,可以幫助您及早控制成本,并減小以后陷入性能問題的可能性。

    改善智能客戶端應(yīng)用程序的性能并不僅限于應(yīng)用程序設(shè)計(jì)問題。您可以在整個(gè)應(yīng)用程序生存期中采取許多個(gè)步驟來使 .NET 代碼具有更高的性能。雖然 .NET 公共語言運(yùn)行庫 (CLR) 在執(zhí)行代碼方面非常有效,但您可以使用多種技術(shù)來提高代碼的性能,并防止在代碼級(jí)引入性能問題。有關(guān)這些問題的詳細(xì)信息,請參閱http://msdn.microsoft.com/perf

    在應(yīng)用程序的設(shè)計(jì)中定義現(xiàn)實(shí)的性能要求并識(shí)別潛在的問題顯然是重要的,但是性能問題通常只在編寫代碼之后對其進(jìn)行測試時(shí)出現(xiàn)。在這種情況下,您可以使用一些工具和技術(shù)來跟蹤性能問題。

    本章分析如何設(shè)計(jì)和調(diào)整您的智能客戶端應(yīng)用程序以獲得最佳性能。它討論了許多設(shè)計(jì)和體系結(jié)構(gòu)問題(包括線程處理和緩存注意事項(xiàng)),并且分析了如何增強(qiáng)應(yīng)用程序的 Windows 窗體部分的性能。本章還介紹了您可以用來跟蹤和診斷智能客戶端應(yīng)用程序性能問題的一些技術(shù)和工具。

    針對性能進(jìn)行設(shè)計(jì)

    您可以在應(yīng)用程序設(shè)計(jì)或體系結(jié)構(gòu)級(jí)完成許多工作,以確保智能客戶端應(yīng)用程序具有良好的性能。您應(yīng)該確保在設(shè)計(jì)階段盡可能早地制定現(xiàn)實(shí)的且可度量的性能目標(biāo),以便評(píng)估設(shè)計(jì)折衷,并且提供最劃算的方法來解決性能問題。只要可能,性能目標(biāo)就應(yīng)該基于實(shí)際的用戶和業(yè)務(wù)要求,因?yàn)檫@些要求受到應(yīng)用程序所處的操作環(huán)境的強(qiáng)烈影響。性能建模是一種結(jié)構(gòu)化的且可重復(fù)的過程,您可以使用該過程來管理您的應(yīng)用程序并確保其實(shí)現(xiàn)性能目標(biāo)。有關(guān)詳細(xì)信息,請參閱 Improving .NET Application Performance and Scalability 中的第 2 章“Performance Modeling”,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt02.asp

    智能客戶端通常是較大的分布式應(yīng)用程序的組成部分。很重要的一點(diǎn)是在完整應(yīng)用程序的上下文中考慮智能客戶端應(yīng)用程序的性能,包括該客戶端應(yīng)用程序使用的所有位于網(wǎng)絡(luò)中的資源。微調(diào)并優(yōu)化應(yīng)用程序中的每一個(gè)組件通常是不必要或不可能的。相反,性能調(diào)整應(yīng)該基于優(yōu)先級(jí)、時(shí)間、預(yù)算約束和風(fēng)險(xiǎn)。一味地追求高性能通常并不是一種劃算的策略。

    智能客戶端還將需要與用戶計(jì)算機(jī)上的其他應(yīng)用程序共存。當(dāng)您設(shè)計(jì)智能客戶端應(yīng)用程序時(shí),您應(yīng)該考慮到您的應(yīng)用程序?qū)⑿枰c客戶端計(jì)算機(jī)上的其他應(yīng)用程序共享系統(tǒng)資源,例如,內(nèi)存、CPU 時(shí)間和網(wǎng)絡(luò)利用率。

    有關(guān)設(shè)計(jì)可伸縮的高性能遠(yuǎn)程服務(wù)的信息,請參閱Improving .NET Performance and Scalability,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenet.asp。本指南包含有關(guān)如何優(yōu)化 .NET 代碼以獲得最佳性能的詳細(xì)信息。

    要設(shè)計(jì)高性能的智能客戶端,請考慮下列事項(xiàng):

    ?

    在適當(dāng)?shù)奈恢镁彺鏀?shù)據(jù)。數(shù)據(jù)緩存可以顯著改善智能客戶端應(yīng)用程序的性能,使您可以在本地使用數(shù)據(jù),而不必經(jīng)常從網(wǎng)絡(luò)檢索數(shù)據(jù)。但是,敏感數(shù)據(jù)或頻繁更改的數(shù)據(jù)通常不適合進(jìn)行緩存。

    ?

    優(yōu)化網(wǎng)絡(luò)通訊。如果通過“健談的”接口與遠(yuǎn)程層服務(wù)進(jìn)行通訊,并且借助于多個(gè)請求/響應(yīng)往返行程來執(zhí)行單個(gè)邏輯操作,則可能消耗系統(tǒng)和網(wǎng)絡(luò)資源,從而導(dǎo)致低劣的應(yīng)用程序性能。

    ?

    有效地使用線程。如果您使用用戶界面 (UI) 線程執(zhí)行阻塞 I/O 綁定調(diào)用,則 UI 似乎不對用戶作出響應(yīng)。因?yàn)閯?chuàng)建和關(guān)閉線程需要系統(tǒng)開銷,所以創(chuàng)建大量不必要的線程可能導(dǎo)致低劣的性能。

    ?

    有效地使用事務(wù)。如果客戶端具有本地?cái)?shù)據(jù),則使用原子事務(wù)可幫助您確保該數(shù)據(jù)是一致的。因?yàn)閿?shù)據(jù)是本地的,所以事務(wù)也是本地的而不是分布式的。對于脫機(jī)工作的智能客戶端而言,對本地?cái)?shù)據(jù)進(jìn)行的任何更改都是暫時(shí)的。客戶端在重新聯(lián)機(jī)時(shí)需要同步更改。對于非本地?cái)?shù)據(jù)而言,在某些情況下可以使用分布式事務(wù)(例如,當(dāng)服務(wù)位于具有良好連接性的同一物理位置并且服務(wù)支持它時(shí))。諸如 Web 服務(wù)和消息隊(duì)列之類的服務(wù)不支持分布式事務(wù)。

    ?

    優(yōu)化應(yīng)用程序啟動(dòng)時(shí)間。較短的應(yīng)用程序啟動(dòng)時(shí)間使用戶可以更為迅速地開始與應(yīng)用程序交互,從而使用戶立刻對應(yīng)用程序的性能和可用性產(chǎn)生好感。應(yīng)該對您的應(yīng)用程序進(jìn)行適當(dāng)?shù)脑O(shè)計(jì),以便在應(yīng)用程序啟動(dòng)時(shí)僅加載那些必需的程序集。因?yàn)榧虞d每個(gè)程序集都會(huì)引起性能開銷,所以請避免使用大量程序集。

    ?

    有效地管理可用資源。低劣的設(shè)計(jì)決策(例如,實(shí)現(xiàn)不必要的完成器,未能在 Dispose 方法中取消終止,或者未能釋放非托管資源)可能導(dǎo)致在回收資源時(shí)發(fā)生不必要的延遲,并且可能造成使應(yīng)用程序性能降低的資源泄漏。如果應(yīng)用程序未能正確地釋放資源,或者應(yīng)用程序顯式強(qiáng)制進(jìn)行垃圾回收,則可能會(huì)妨礙 CLR 有效地管理內(nèi)存。

    ?

    優(yōu)化 Windows 窗體性能。智能客戶端應(yīng)用程序依靠 Windows 窗體來提供內(nèi)容豐富且響應(yīng)迅速的用戶界面.您可以使用多種技術(shù)來確保 Windows 窗體提供最佳性能。這些技術(shù)包括降低用戶界面的復(fù)雜性,以及避免同時(shí)加載大量數(shù)據(jù)。

    在許多情況下,從用戶角度感受到的應(yīng)用程序性能起碼與應(yīng)用程序的實(shí)際性能同樣重要。您可以通過對設(shè)計(jì)進(jìn)行某些特定的更改來創(chuàng)建在用戶看來性能高得多的應(yīng)用程序,例如:使用后臺(tái)異步處理(以使 UI 能作出響應(yīng));顯示進(jìn)度欄以指示任務(wù)的進(jìn)度;提供相應(yīng)的選項(xiàng)以便用戶取消長期運(yùn)行的任務(wù)。

    本節(jié)將專門詳細(xì)討論這些問題。

    數(shù)據(jù)緩存原則

    緩存是一種能夠改善應(yīng)用程序性能并提供響應(yīng)迅速的用戶界面的重要技術(shù)。您應(yīng)該考慮下列選項(xiàng):

    ?

    緩存頻繁檢索的數(shù)據(jù)以減少往返行程。如果您的應(yīng)用程序必須頻繁地與網(wǎng)絡(luò)服務(wù)交互以檢索數(shù)據(jù),則應(yīng)該考慮在客戶端緩存數(shù)據(jù),從而減少通過網(wǎng)絡(luò)重復(fù)獲取數(shù)據(jù)的需要。這可以極大地提高性能,提供對數(shù)據(jù)的近乎即時(shí)的訪問,并且消除了可能對智能客戶端應(yīng)用程序性能造成不利影響的網(wǎng)絡(luò)延遲和中斷風(fēng)險(xiǎn)。

    ?

    緩存只讀引用數(shù)據(jù)。只讀引用數(shù)據(jù)通常是理想的緩存對象。此類數(shù)據(jù)用于提供進(jìn)行驗(yàn)證和用戶界面顯示所需的數(shù)據(jù),例如,產(chǎn)品說明、ID 等等。因?yàn)榭蛻舳藷o法更改此類數(shù)據(jù),所以通常可以在客戶端緩存它而無須進(jìn)行任何進(jìn)一步的特殊處理。

    ?

    緩存要發(fā)送給位于網(wǎng)絡(luò)上的服務(wù)的數(shù)據(jù)。您應(yīng)該考慮緩存要發(fā)送給位于網(wǎng)絡(luò)上的服務(wù)的數(shù)據(jù)。例如,如果您的應(yīng)用程序允許用戶輸入由在多個(gè)窗體中收集的一些離散數(shù)據(jù)項(xiàng)組成的定單信息,則請考慮允許用戶輸入全部數(shù)據(jù),然后在輸入過程的結(jié)尾在一個(gè)網(wǎng)絡(luò)調(diào)用中發(fā)送定單信息。

    ?

    盡量少地緩存高度不穩(wěn)定的數(shù)據(jù)。在緩存任何不穩(wěn)定的數(shù)據(jù)之前,您需要考慮在其變得陳舊或者由于其他原因變得不可用之前,能夠?qū)⑵渚彺娑嚅L時(shí)間。如果數(shù)據(jù)高度不穩(wěn)定并且您的應(yīng)用程序依賴于最新信息,則或許只能將數(shù)據(jù)緩存很短一段時(shí)間(如果可以緩存)。

    ?

    盡量少地緩存敏感數(shù)據(jù)。您應(yīng)該避免在客戶端上緩存敏感數(shù)據(jù),因?yàn)樵诖蠖鄶?shù)情況下,您無法保證客戶端的物理安全。但是,如果您必須在客戶端上緩存敏感數(shù)據(jù),則您通常將需要加密數(shù)據(jù),該操作本身也會(huì)影響性能。

    有關(guān)數(shù)據(jù)緩存的其他問題的詳細(xì)信息,請參閱本指南的第 2 章。另請參閱 Improving .NET Application Performance and Scalability 的第 3 章“Design Guidelines for Application Performance”(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt03.asp) 的“Caching”一節(jié)以及 Improving .NET Application Performance and Scalability 的第 4 章“Architecture and Design Review of .NET Application for Performance and Scalability”(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt04.asp)。

    網(wǎng)絡(luò)通訊原則

    您將面臨的另一個(gè)決策是如何設(shè)計(jì)和使用網(wǎng)絡(luò)服務(wù),例如,Web 服務(wù)。特別地,您應(yīng)該考慮與網(wǎng)絡(luò)服務(wù)交互的粒度、同步性和頻率。要獲得最佳的性能和可伸縮性,您應(yīng)該在單個(gè)調(diào)用中發(fā)送更多的數(shù)據(jù),而不是在多個(gè)調(diào)用中發(fā)送較少量的數(shù)據(jù)。例如,如果您的應(yīng)用程序允許用戶在定單中輸入多個(gè)項(xiàng),則較好的做法是為所有項(xiàng)收集數(shù)據(jù),然后將完成的采購定單一次性發(fā)送給服務(wù),而不是在多個(gè)調(diào)用中發(fā)送單個(gè)項(xiàng)的詳細(xì)信息。除了降低與進(jìn)行大量網(wǎng)絡(luò)調(diào)用相關(guān)聯(lián)的系統(tǒng)開銷以外,這還可以減少服務(wù)和/或客戶端內(nèi)的復(fù)雜狀態(tài)管理的需要。

    應(yīng)該將您的智能客戶端應(yīng)用程序設(shè)計(jì)為盡可能地使用異步通訊,因?yàn)檫@將有助于使用戶界面快速響應(yīng)以及并行執(zhí)行任務(wù)。有關(guān)如何使用 BeginInvokeEndInvoke 方法異步啟動(dòng)調(diào)用和檢索數(shù)據(jù)的詳細(xì)信息,請參閱“Asynchronous Programming Overview”(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpovrasynchronousprogrammingoverview.asp)。

    有關(guān)設(shè)計(jì)和構(gòu)建偶爾連接到網(wǎng)絡(luò)的智能客戶端應(yīng)用程序的詳細(xì)信息,請參閱第 3 章“建立連接”第 4 章“偶爾連接的智能客戶端”

    線程處理原則

    在應(yīng)用程序內(nèi)使用多個(gè)線程可能是一種提高其響應(yīng)性和性能的好方法。特別地,您應(yīng)該考慮使用線程來執(zhí)行可以在后臺(tái)安全地完成且不需要用戶交互的處理。通過在后臺(tái)執(zhí)行此類工作,可以使用戶能夠繼續(xù)使用應(yīng)用程序,并且使應(yīng)用程序的主用戶界面線程能夠維持應(yīng)用程序的響應(yīng)性。

    適合于在單獨(dú)的線程上完成的處理包括:

    ?

    應(yīng)用程序初始化。請?jiān)诤笈_(tái)線程上執(zhí)行漫長的初始化,以便用戶能夠盡快地與您的應(yīng)用程序交互,尤其是在應(yīng)用程序功能的重要或主要部分并不依賴于該初始化完成時(shí)。

    ?

    遠(yuǎn)程服務(wù)調(diào)用。請?jiān)趩为?dú)的后臺(tái)線程上通過網(wǎng)絡(luò)進(jìn)行所有遠(yuǎn)程調(diào)用。很難(如果不是無法)保證位于網(wǎng)絡(luò)上的服務(wù)的響應(yīng)時(shí)間。在單獨(dú)的線程上執(zhí)行這些調(diào)用可以減少發(fā)生網(wǎng)絡(luò)中斷或延遲的風(fēng)險(xiǎn),從而避免對應(yīng)用程序性能造成不利影響。

    ?

    IO 綁定處理。應(yīng)該在單獨(dú)的線程上完成諸如在磁盤上搜索和排序數(shù)據(jù)之類的處理。通常,這種工作要受到磁盤 I/O 子系統(tǒng)而不是處理器可用性的限制,因此當(dāng)該工作在后臺(tái)執(zhí)行時(shí),您的應(yīng)用程序可以有效地維持其響應(yīng)性。

    盡管使用多個(gè)線程的性能好處可能很顯著,但需要注意,線程使用它們自己的資源,并且使用太多的線程可能給處理器(它需要管理線程之間的上下文切換)造成負(fù)擔(dān)。要避免這一點(diǎn),請考慮使用線程池,而不是創(chuàng)建和管理您自己的線程。線程池將為您有效地管理線程,重新使用現(xiàn)有的線程對象,并且盡可能地減小與線程創(chuàng)建和處置相關(guān)聯(lián)的系統(tǒng)開銷。

    如果用戶體驗(yàn)受到后臺(tái)線程所執(zhí)行的工作的影響,則您應(yīng)該總是讓用戶了解工作的進(jìn)度。以這種方式提供反饋可以增強(qiáng)用戶對您的應(yīng)用程序的性能的感覺,并且防止他或她假設(shè)沒有任何事情發(fā)生。請努力確保用戶可以隨時(shí)取消漫長的操作。

    您還應(yīng)該考慮使用 Application 對象的 Idle 事件來執(zhí)行簡單的操作。Idle 事件提供了使用單獨(dú)的線程來進(jìn)行后臺(tái)處理的簡單替代方案。當(dāng)應(yīng)用程序不再有其他用戶界面消息需要處理并且將要進(jìn)入空閑狀態(tài)時(shí),該事件將激發(fā)。您可以通過該事件執(zhí)行簡單的操作,并且利用用戶不活動(dòng)的情況。例如:

    [C#]

    public Form1() 
    { 
    InitializeComponent(); 
    Application.Idle += new EventHandler( OnApplicationIdle ); 
    } 
    private void OnApplicationIdle( object sender, EventArgs e ) 
    { 
    } 
    

    [Visual Basic .NET]

    Public Class Form1 
        Inherits System.Windows.Forms.Form 
        Public Sub New() 
            MyBase.New() 
            InitializeComponent() 
            AddHandler Application.Idle, AddressOf OnApplicationIdle 
        End Sub 
        Private Sub OnApplicationIdle(ByVal sender As System.Object, ByVal e As System.EventArgs) 
        End Sub 
    End Class 
    

    有關(guān)在智能客戶端中使用多個(gè)線程的詳細(xì)信息,請參閱第 6 章“使用多個(gè)線程”

    事務(wù)原則

    事務(wù)可以提供重要的支持,以確保不會(huì)違反業(yè)務(wù)規(guī)則并維護(hù)數(shù)據(jù)一致性。事務(wù)可以確保一組相關(guān)任務(wù)作為一個(gè)單元成功或失敗。您可以使用事務(wù)來維護(hù)本地?cái)?shù)據(jù)庫和其他資源(包括消息隊(duì)列的隊(duì)列)之間的一致性。

    對于需要在網(wǎng)絡(luò)連接不可用時(shí)使用脫機(jī)緩存數(shù)據(jù)的智能客戶端應(yīng)用程序,您應(yīng)該將事務(wù)性數(shù)據(jù)排隊(duì),并且在網(wǎng)絡(luò)連接可用時(shí)將其與服務(wù)器進(jìn)行同步。

    您應(yīng)該避免使用涉及到位于網(wǎng)絡(luò)上的資源的分布式事務(wù),因?yàn)檫@些情況可能導(dǎo)致與不斷變化的網(wǎng)絡(luò)和資源響應(yīng)時(shí)間有關(guān)的性能問題。如果您的應(yīng)用程序需要在事務(wù)中涉及到位于網(wǎng)絡(luò)上的資源,則應(yīng)該考慮使用補(bǔ)償事務(wù),以便使您的應(yīng)用程序能夠在本地事務(wù)失敗時(shí)取消以前的請求。盡管補(bǔ)償事務(wù)在某些情況下可能不適用,但它們使您的應(yīng)用程序能夠按照松耦合方式在事務(wù)的上下文內(nèi)與網(wǎng)絡(luò)資源交互,從而減少了不在本地計(jì)算機(jī)控制之下的資源對應(yīng)用程序的性能造成不利影響的可能性。

    有關(guān)在智能客戶端中使用事務(wù)的詳細(xì)信息,請參閱第 3 章“建立連接”

    優(yōu)化應(yīng)用程序啟動(dòng)時(shí)間

    快速的應(yīng)用程序啟動(dòng)時(shí)間幾乎可以使用戶立即開始與應(yīng)用程序交互,從而使用戶立刻對應(yīng)用程序的性能和可用性產(chǎn)生好感。

    當(dāng)應(yīng)用程序啟動(dòng)時(shí),首先加載 CLR,再加載應(yīng)用程序的主程序集,隨后加載為解析從應(yīng)用程序的主窗體中引用的對象的類型所需要的所有程序集。CLR 在該階段不會(huì) 加載所有相關(guān)程序集;它僅加載包含主窗體類上的成員變量的類型定義的程序集。在加載了這些程序集之后,實(shí)時(shí) (JIT) 編譯器將在方法運(yùn)行時(shí)編譯方法的代碼(從 Main 方法開始)。同樣,JIT 編譯器不會(huì) 編譯您的程序集中的所有代碼。相反,將根據(jù)需要逐個(gè)方法地編譯代碼。

    要盡可能減少應(yīng)用程序的啟動(dòng)時(shí)間,您應(yīng)該遵循下列原則:

    ?

    盡可能減少應(yīng)用程序主窗體類中的成員變量。這將在 CLR 加載主窗體類時(shí)盡可能減少必須解析的類型數(shù)量。

    ?

    盡量不要立即使用大型基類程序集(XML 庫或 ADO.NET 庫)中的類型。這些程序集的加載很費(fèi)時(shí)間。使用應(yīng)用程序配置類和跟蹤開關(guān)功能時(shí)將引入 XML 庫。如果要優(yōu)先考慮應(yīng)用程序啟動(dòng)時(shí)間,請避免這一點(diǎn)。

    ?

    盡可能使用惰性加載。僅在需要時(shí)獲取數(shù)據(jù),而不是提前加載和凍結(jié) UI。

    ?

    將應(yīng)用程序設(shè)計(jì)為使用較少的程序集。帶有大量程序集的應(yīng)用程序會(huì)招致性能開銷增加。這些開銷來自加載元數(shù)據(jù)、訪問 CLR 中的預(yù)編譯映像中的各種內(nèi)存頁以加載程序集(如果它是用本機(jī)映像生成器工具 Ngen.exe 預(yù)編譯的)、JIT 編譯時(shí)間、安全檢查等等。您應(yīng)該考慮基于程序集的使用模式來合并程序集,以便降低相關(guān)聯(lián)的性能開銷。

    ?

    避免設(shè)計(jì)將多個(gè)組件的功能組合到一個(gè)組件中的單一類。將設(shè)計(jì)分解到多個(gè)只須在實(shí)際調(diào)用時(shí)進(jìn)行編譯的較小類。

    ?

    將應(yīng)用程序設(shè)計(jì)為在初始化期間對網(wǎng)絡(luò)服務(wù)進(jìn)行并行調(diào)用。通過在初始化期間調(diào)用可以并行運(yùn)行的網(wǎng)絡(luò)服務(wù),可以利用服務(wù)代理提供的異步功能。這有助于釋放當(dāng)前執(zhí)行的線程并且并發(fā)地調(diào)用服務(wù)以完成任務(wù)。

    ?

    使用 NGEN.exe 編譯和試驗(yàn) NGen 和非 NGen 程序集,并且確定哪個(gè)程序集保存了最大數(shù)量的工作集頁面。NGEN.exe(它隨附在 .NET Framework 中)用于預(yù)編譯程序集以創(chuàng)建本機(jī)映像,該映像隨后被存儲(chǔ)在全局程序集緩存的特殊部分,以便應(yīng)用程序下次需要它時(shí)使用。通過創(chuàng)建程序集的本機(jī)映像,可以使程序集更快地加載和執(zhí)行,因?yàn)?CLR 不需要?jiǎng)討B(tài)生成程序集中包含的代碼和數(shù)據(jù)結(jié)構(gòu)。有關(guān)詳細(xì)信息,請參閱 Improving .NET Application Performance and Scalability 的第 5 章“Improving Managed Code Performance”中的“Working Set Considerations”和“NGen.exe Explained”部分,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt05.asp

    如果您使用 NGEN 預(yù)編譯程序集,則會(huì)立即加載它的所有依賴程序集。

    管理可用資源

    公共語言運(yùn)行庫 (CLR) 使用垃圾回收器來管理對象生存期和內(nèi)存使用。這意味著無法再訪問的對象將被垃圾回收器自動(dòng)回收,并且自動(dòng)回收內(nèi)存。由于多種原因無法再訪問對象。例如,可能沒有對該對象的任何引用,或者對該對象的所有引用可能來自其他可作為當(dāng)前回收周期的一部分進(jìn)行回收的對象。盡管自動(dòng)垃圾回收使您的代碼不必負(fù)責(zé)管理對象刪除,但這意味著您的代碼不再對對象的確切刪除時(shí)間具有顯式控制。

    請考慮下列原則,以確保您能夠有效地管理可用資源:

    ?

    確保在被調(diào)用方對象提供 Dispose 方法時(shí)該方法得到調(diào)用。如果您的代碼調(diào)用了支持 Dispose 方法的對象,則您應(yīng)該確保在使用完該對象之后立即調(diào)用此方法。調(diào)用 Dispose 方法可以確保搶先釋放非托管資源,而不是等到發(fā)生垃圾回收。除了提供 Dispose 方法以外,某些對象還提供其他管理資源的方法,例如,Close 方法。在這些情況下,您應(yīng)該參考文檔資料以了解如何使用其他方法。例如,對于 SqlConnection 對象而言,調(diào)用 CloseDispose 都足可以搶先將數(shù)據(jù)庫連接釋放回連接池中。一種可以確保您在對象使用完畢之后立即調(diào)用 Dispose 的方法是使用 Visual C# .NET 中的 using 語句或 Visual Basic .NET 中的 Try/Finally 塊。

    下面的代碼片段演示了 Dispose 的用法。

    C# 中的 using 語句示例:

    using( StreamReader myFile = new StreamReader("C:\\ReadMe.Txt")){ 
    string contents = myFile.ReadToEnd(); 
    //... use the contents of the file 
    } // dispose is called and the StreamReader's resources released 
    

    Visual Basic .NET 中的 Try/Finally 塊示例:

    Dim myFile As StreamReader 
    myFile = New StreamReader("C:\\ReadMe.Txt") 
    Try 
    String contents = myFile.ReadToEnd() 
    '... use the contents of the file 
    Finally 
    myFile.Close() 
    End Try 
    

    在 C# 和 C++ 中,F(xiàn)inalize 方法是作為析構(gòu)函數(shù)實(shí)現(xiàn)的。在 Visual Basic .NET 中,Finalize 方法是作為 Object 基類上的 Finalize 子例程的重寫實(shí)現(xiàn)的。

    ?

    如果您在客戶端調(diào)用過程中占據(jù)非托管資源,則請?zhí)峁?/B> Finalize Dispose 方法。如果您在公共或受保護(hù)的方法調(diào)用中創(chuàng)建訪問非托管資源的對象,則應(yīng)用程序需要控制非托管資源的生存期。在圖 8.1 中,第一種情況是對非托管資源的調(diào)用,在此將打開、獲取和關(guān)閉資源。在此情況下,您的對象無須提供 FinalizeDispose 方法。在第二種情況下,在方法調(diào)用過程中占據(jù)非托管資源;因此,您的對象應(yīng)該提供 FinalizeDispose 方法,以便客戶端在使用完該對象后可以立即顯式釋放資源。

    ppt-pic_f01

    8.1Dispose Finalize 方法調(diào)用的用法

    垃圾回收通常有利于提高總體性能,因?yàn)樗鼘⑺俣鹊闹匾灾糜趦?nèi)存利用率之上。只有當(dāng)內(nèi)存資源不足時(shí),才需要?jiǎng)h除對象;否則,將使用所有可用的應(yīng)用程序資源以使您的應(yīng)用程序受益。但是,如果您的對象保持對非托管資源(例如,窗口句柄、文件、GDI 對象和網(wǎng)絡(luò)連接)的引用,則程序員通過在這些資源不再使用時(shí)顯式釋放它們可以獲得更好的性能。如果您要在客戶端方法調(diào)用過程中占據(jù)非托管資源,則對象應(yīng)該允許調(diào)用方使用 IDisposable 接口(它提供 Dispose 方法)顯式管理資源。通過實(shí)現(xiàn) IDisposable,對象將通知它可被要求明確進(jìn)行清理,而不是等待垃圾回收。實(shí)現(xiàn) IDisposable 的對象的調(diào)用方在使用完該對象后將簡單地調(diào)用 Dispose 方法,以便它可以根據(jù)需要釋放資源。

    有關(guān)如何在某個(gè)對象上實(shí)現(xiàn) IDisposable 的詳細(xì)信息,請參閱 Improving .NET Application Performance and Scalability 中的第 5 章“Improving Managed Code Performance”,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt05.asp

    如果您的可處置對象派生自另一個(gè)也實(shí)現(xiàn)了 IDisposable 接口的對象,則您應(yīng)該調(diào)用基類的 Dispose 方法以使其可以清理它的資源。您還應(yīng)該調(diào)用實(shí)現(xiàn)了 IDisposable 接口的對象所擁有的所有對象上的 Dispose

    Finalize 方法也使您的對象可以在刪除時(shí)顯式釋放其引用的任何資源。由于垃圾回收器所具有的非確定性,在某些情況下,Finalize 方法可能長時(shí)間不會(huì)被調(diào)用。實(shí)際上,如果您的應(yīng)用程序在垃圾回收器刪除對象之前終止,則該方法可能永遠(yuǎn)不會(huì)被調(diào)用。然而,需要使用 Finalize 方法作為一種后備策略,以防調(diào)用方?jīng)]有顯式調(diào)用 Dispose 方法(DisposeFinalize 方法共享相同的資源清理代碼)。通過這種方式,可能在某個(gè)時(shí)刻釋放資源,即使這發(fā)生在最佳時(shí)刻之后。

    要確保 Dispose 和 Finalize 中的清理代碼不會(huì)被調(diào)用兩次,您應(yīng)該調(diào)用 GC.SuppressFinalize 以通知垃圾回收器不要調(diào)用 Finalize 方法。

    垃圾回收器實(shí)現(xiàn)了 Collect 方法,該方法強(qiáng)制垃圾回收器刪除所有對象掛起刪除。不應(yīng)該從應(yīng)用程序內(nèi)調(diào)用該方法,因?yàn)榛厥罩芷谠诟邇?yōu)先級(jí)線程上運(yùn)行。回收周期可能凍結(jié)所有 UI 線程,從而使得用戶界面停止響應(yīng)。

    有關(guān)詳細(xì)信息,請參閱 Improving .NET Application Performance and Scalability 中的“Garbage Collection Guidelines”、“Finalize and Dispose Guidelines”、“Dispose Pattern”和“Finalize and Dispose Guidelines”,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt05.asp

    優(yōu)化 Windows 窗體性能

    Windows 窗體為智能客戶端應(yīng)用程序提供了內(nèi)容豐富的用戶界面,并且您可以使用許多種技術(shù)來幫助確保 Windows 窗體提供最佳性能。在討論特定技術(shù)之前,對一些可以顯著提高 Windows 窗體性能的高級(jí)原則進(jìn)行回顧是有用的。

    ?

    小心創(chuàng)建句柄。Windows 窗體將句柄創(chuàng)建虛擬化(即,它動(dòng)態(tài)創(chuàng)建和重新創(chuàng)建窗口句柄對象)。創(chuàng)建句柄對象的系統(tǒng)開銷可能非常大;因此,請避免進(jìn)行不必要的邊框樣式更改或者更改 MDI 父對象。

    ?

    避免創(chuàng)建帶有太多子控件的應(yīng)用程序。Microsoft? Windows? 操作系統(tǒng)限制每個(gè)進(jìn)程最多有 10,000 個(gè)控件,但您應(yīng)該避免在窗體上使用成百上千個(gè)控件,因?yàn)槊總€(gè)控件都要消耗內(nèi)存資源。

    本節(jié)的其余部分討論您可以用來優(yōu)化應(yīng)用程序用戶界面性能的更為具體的技術(shù)。

    使用 BeginUpdate 和 EndUpdate

    許多 Windows 窗體控件(例如,ListViewTreeView 控件)實(shí)現(xiàn)了 BeginUpdateEndUpdate 方法,它們在操縱基礎(chǔ)數(shù)據(jù)或控件屬性時(shí)取消了控件的重新繪制。通過使用 BeginUpdateEndUpdate 方法,您可以對控件進(jìn)行重大更改,并且避免在應(yīng)用這些更改時(shí)讓控件經(jīng)常重新繪制自身。此類重新繪制會(huì)導(dǎo)致性能顯著降低,并且用戶界面閃爍且不反應(yīng)。

    例如,如果您的應(yīng)用程序具有一個(gè)要求添加大量節(jié)點(diǎn)項(xiàng)的樹控件,則您應(yīng)該調(diào)用 BeginUpdate,添加所有必需的節(jié)點(diǎn)項(xiàng),然后調(diào)用 EndUpdate。下面的代碼示例顯示了一個(gè)樹控件,該控件用于顯示許多個(gè)客戶的層次結(jié)構(gòu)表示形式及其定單信息。

    [C#]

    // Suppress repainting the TreeView until all the objects have been created. 
    TreeView1.BeginUpdate(); 
    // Clear the TreeView. 
    TreeView1.Nodes.Clear(); 
    // Add a root TreeNode for each Customer object in the ArrayList. 
    foreach( Customer customer2 in customerArray ) 
    { 
        TreeView1.Nodes.Add( new TreeNode( customer2.CustomerName ) ); 
        // Add a child TreeNode for each Order object in the current Customer. 
        foreach( Order order1 in customer2.CustomerOrders ) 
        { 
            TreeView1.Nodes[ customerArray.IndexOf(customer2) ].Nodes.Add( 
                 new TreeNode( customer2.CustomerName + "." + order1.OrderID ) ); 
        } 
    } 
    // Begin repainting the TreeView. 
    TreeView1.EndUpdate(); 
    

    [Visual Basic .NET]

           ' Suppress repainting the TreeView until all the objects have been created. 
            TreeView1.BeginUpdate() 
    ' Clear the TreeView 
    TreeView1.Nodes.Clear() 
    ' Add a root TreeNode for each Customer object in the ArrayList 
    For Each customer2 As Customer In customerArray 
         TreeView1.Nodes.Add(New TreeNode(customer2.CustomerName)) 
         ' Add a child TreeNode for each Order object in the current Customer. 
         For Each order1 As Order In customer2.CustomerOrders 
               TreeView1.Nodes(Array.IndexOf(customerArray, customer2)).Nodes.Add( _ 
                        New TreeNode(customer2.CustomerName & "." & order1.OrderID)) 
         Next 
    Next 
    ' Begin repainting the TreeView. 
    TreeView1.EndUpdate() 
    

    即使在您不希望向控件添加許多對象時(shí),您也應(yīng)該使用 BeginUpdateEndUpdate 方法。在大多數(shù)情況下,您在運(yùn)行之前將不知道要添加的項(xiàng)的確切個(gè)數(shù)。因此,為了妥善處理大量數(shù)據(jù)以及應(yīng)付將來的要求,您應(yīng)該總是調(diào)用 BeginUpdateEndUpdate 方法。

    調(diào)用 Windows 窗體控件使用的許多 Collection 類的 AddRange 方法時(shí),將自動(dòng)為您調(diào)用 BeginUpdateEndUpdate 方法。

    使用 SuspendLayout 和 ResumeLayout

    許多 Windows 窗體控件(例如,ListViewTreeView 控件)都實(shí)現(xiàn)了 SuspendLayoutResumeLayout 方法,它們能夠防止控件在添加子控件時(shí)創(chuàng)建多個(gè)布局事件。

    如果您的控件以編程方式添加和刪除子控件或者執(zhí)行動(dòng)態(tài)布局,則您應(yīng)該調(diào)用 SuspendLayoutResumeLayout 方法。通過 SuspendLayout 方法,可以在控件上執(zhí)行多個(gè)操作,而不必為每個(gè)更改執(zhí)行布局。例如,如果您調(diào)整控件的大小并移動(dòng)控件,則每個(gè)操作都將引發(fā)單獨(dú)的布局事件。

    這些方法按照與 BeginUpdateEndUpdate 方法類似的方式操作,并且在性能和用戶界面穩(wěn)定性方面提供相同的好處。

    下面的示例以編程方式向父窗體中添加按鈕:

    [C#]

    private void AddButtons() 
    { 
      // Suspend the form layout and add two buttons. 
      this.SuspendLayout(); 
      Button buttonOK = new Button(); 
      buttonOK.Location = new Point(10, 10); 
      buttonOK.Size = new Size(75, 25); 
      buttonOK.Text = "OK"; 
      Button buttonCancel = new Button(); 
      buttonCancel.Location = new Point(90, 10); 
      buttonCancel.Size = new Size(75, 25); 
      buttonCancel.Text = "Cancel"; 
      this.Controls.AddRange(new Control[]{buttonOK, buttonCancel}); 
      this.ResumeLayout(); 
    } 
    

    [Visual Basic .NET]

    Private Sub AddButtons() 
            ' Suspend the form layout and add two buttons 
            Me.SuspendLayout() 
            Dim buttonOK As New Button 
            buttonOK.Location = New Point(10, 10) 
            buttonOK.Size = New Size(75, 25) 
            buttonOK.Text = "OK" 
            Dim buttonCancel As New Button 
            buttonCancel.Location = New Point(90, 10) 
            buttonCancel.Size = New Size(75, 25) 
            buttonCancel.Text = "Cancel" 
            Me.Controls.AddRange(New Control() { buttonOK, buttonCancel } ) 
            Me.ResumeLayout() 
    End Sub 
    

    每當(dāng)您添加或刪除控件、執(zhí)行子控件的自動(dòng)布局或者設(shè)置任何影響控件布局的屬性(例如,大小、位置、定位點(diǎn)或停靠屬性)時(shí),您都應(yīng)該使用 SuspendLayoutResumeLayout 方法。

    處理圖像

    如果您的應(yīng)用程序顯示大量圖像文件(例如,.jpg 和 .gif 文件),則您可以通過以位圖格式預(yù)先呈現(xiàn)圖像來顯著改善顯示性能。

    要使用該技術(shù),請首先從文件中加載圖像,然后使用 PARGB 格式將其呈現(xiàn)為位圖。下面的代碼示例從磁盤中加載文件,然后使用該類將圖像呈現(xiàn)為預(yù)乘的、Alpha 混合 RGB 格式。例如:

    [C#]

    if ( image != null && image is Bitmap ) 
    { 
    Bitmap bm = (Bitmap)image; 
    Bitmap newImage = new Bitmap( bm.Width, bm.Height, 
       System.Drawing.Imaging.PixelFormat.Format32bppPArgb ); 
    using ( Graphics g = Graphics.FromImage( newImage ) ) 
    { 
    g.DrawImage( bm, new Rectangle( 0,0, bm.Width, bm.Height ) ); 
    } 
    image = newImage; 
    } 
    

    [Visual Basic .NET]

            If Not(image Is Nothing)  AndAlso (TypeOf image Is Bitmap) Then 
                Dim bm As Bitmap = CType(image, Bitmap) 
                Dim newImage As New Bitmap(bm.Width, bm.Height, _ 
                    System.Drawing.Imaging.PixelFormat.Format32bppPArgb) 
                Using g As Graphics = Graphics.FromImage(newImage) 
                    g.DrawImage(bm, New Rectangle(0, 0, bm.Width, bm.Height)) 
                End Using 
                image = newImage 
            End If 
    

    使用分頁和惰性加載

    在大多數(shù)情況下,您應(yīng)該僅在需要時(shí)檢索或顯示數(shù)據(jù)。如果您的應(yīng)用程序需要檢索和顯示大量信息,則您應(yīng)該考慮將數(shù)據(jù)分解到多個(gè)頁面中,并且一次顯示一頁數(shù)據(jù)。這可以使用戶界面具有更高的性能,因?yàn)樗鼰o須顯示大量數(shù)據(jù)。此外,這可以提高應(yīng)用程序的可用性,因?yàn)橛脩舨粫?huì)同時(shí)面對大量數(shù)據(jù),并且可以更加容易地導(dǎo)航以查找他或她需要的確切數(shù)據(jù)。

    例如,如果您的應(yīng)用程序顯示來自大型產(chǎn)品目錄的產(chǎn)品數(shù)據(jù),則您可以按照字母順序顯示這些項(xiàng),并且將所有以“A”開頭的產(chǎn)品顯示在一個(gè)頁面上,將所有以“B”開頭的產(chǎn)品顯示在下一個(gè)頁面上。然后,您可以讓用戶直接導(dǎo)航到適當(dāng)?shù)捻撁妫员闼蛩裏o須瀏覽所有頁面就可以獲得他或她需要的數(shù)據(jù)。

    以這種方式將數(shù)據(jù)分頁還使您可以根據(jù)需要獲取后臺(tái)的數(shù)據(jù)。例如,您可能只需要獲取第一頁信息以便顯示并且讓用戶與其進(jìn)行交互。然后,您可以獲取后臺(tái)中的、已經(jīng)準(zhǔn)備好供用戶使用的下一頁數(shù)據(jù)。該技術(shù)在與數(shù)據(jù)緩存技術(shù)結(jié)合使用時(shí)可能特別有效。

    您還可以通過使用惰性加載技術(shù)來提高智能客戶端應(yīng)用程序的性能。您無須立即加載可能在將來某個(gè)時(shí)刻需要的數(shù)據(jù)或資源,而是可以根據(jù)需要加載它們。您可以在構(gòu)建大型列表或樹結(jié)構(gòu)時(shí)使用惰性加載來提高用戶界面的性能。在此情況下,您可以在用戶需要看到數(shù)據(jù)時(shí)(例如,在用戶展開樹節(jié)點(diǎn)時(shí))加載它。

    優(yōu)化顯示速度

    根據(jù)您用于顯示用戶界面控件和應(yīng)用程序窗體的技術(shù),您可以用多種不同的方式來優(yōu)化應(yīng)用程序的顯示速度。

    當(dāng)您的應(yīng)用程序啟動(dòng)時(shí),您應(yīng)該考慮盡可能地顯示簡單的用戶界面。這將減少啟動(dòng)時(shí)間,并且向用戶呈現(xiàn)整潔且易于使用的用戶界面。而且,您應(yīng)該努力避免引用類以及在啟動(dòng)時(shí)加載任何不會(huì)立刻需要的數(shù)據(jù)。這將減少應(yīng)用程序和 .NET Framework 初始化時(shí)間,并且提高應(yīng)用程序的顯示速度。

    當(dāng)您需要顯示對話框或窗體時(shí),您應(yīng)該在它們做好顯示準(zhǔn)備之前使其保持隱藏狀態(tài),以便減少需要的繪制工作量。這將有助于確保窗體僅在初始化之后顯示。

    如果您的應(yīng)用程序具有的控件含有覆蓋整個(gè)客戶端表面區(qū)域的子控件,則您應(yīng)該考慮將控件背景樣式設(shè)置為不透明。這可以避免在發(fā)生每個(gè)繪制事件時(shí)重繪控件的背景。您可以通過使用 SetStyle 方法來設(shè)置控件的樣式。使用 ControlsStyles.Opaque 枚舉可以指定不透明控件樣式。

    您應(yīng)該避免任何不必要的控件重新繪制操作。一種方法是在設(shè)置控件的屬性時(shí)隱藏控件。在 OnPaint 事件中具有復(fù)雜繪圖代碼的應(yīng)用程序能夠只重繪窗體的無效區(qū)域,而不是繪制整個(gè)窗體。OnPaint 事件的 PaintEventArgs 參數(shù)包含一個(gè) ClipRect 結(jié)構(gòu),它指示窗口的哪個(gè)部分無效。這可以減少用戶等待查看完整顯示的時(shí)間。

    使用標(biāo)準(zhǔn)的繪圖優(yōu)化,例如,剪輯、雙緩沖和 ClipRectangle。這還將通過防止對不可見或要求重繪的顯示部分執(zhí)行不必要的繪制操作,從而有助于改善智能客戶端應(yīng)用程序的顯示性能。有關(guān)增強(qiáng)繪圖性能的詳細(xì)信息,請參閱 Painting techniques using Windows Forms for the Microsoft .NET Framework,網(wǎng)址為:http://windowsforms.net/articles/windowsformspainting.aspx

    如果您的顯示包含動(dòng)畫或者經(jīng)常更改某個(gè)顯示元素,則您應(yīng)該使用雙緩沖或多緩沖,在繪制當(dāng)前圖像的過程中準(zhǔn)備下一個(gè)圖像。System.Windows.Forms 命名空間中的 ControlStyles 枚舉適用于許多控件,并且 DoubleBuffer 成員可以幫助防止閃爍。啟用 DoubleBuffer 樣式將使您的控件繪制在離屏緩沖中完成,然后同時(shí)繪制到屏幕上。盡管這有助于防止閃爍,但它的確為分配的緩沖區(qū)使用了更多內(nèi)存。

    返回頁首返回頁首

    性能調(diào)整和診斷

    在設(shè)計(jì)和實(shí)現(xiàn)階段處理性能問題是實(shí)現(xiàn)應(yīng)用程序性能目標(biāo)的最劃算的方法。但是,您只有在開發(fā)階段經(jīng)常且盡早測試應(yīng)用程序的性能,才能真正有效地優(yōu)化應(yīng)用程序的性能。

    盡管針對性能進(jìn)行設(shè)計(jì)和測試都很重要,但在這些早期階段優(yōu)化每個(gè)組件和所有代碼不是有效的資源用法,因此應(yīng)該予以避免。所以,應(yīng)用程序可能存在您在設(shè)計(jì)階段未預(yù)料到的性能問題。例如,您可能遇到由于兩個(gè)系統(tǒng)或組件之間的無法預(yù)料的交互而產(chǎn)生的性能問題,或者您可能使用原來存在的、未按希望的方式執(zhí)行的代碼。在此情況下,您需要追究性能問題的根源,以便您可以適當(dāng)?shù)亟鉀Q該問題。

    本節(jié)討論一些將幫助您診斷性能問題以及調(diào)整應(yīng)用程序以獲得最佳性能的工具和技術(shù)。

    制定性能目標(biāo)

    當(dāng)您設(shè)計(jì)和規(guī)劃智能客戶端應(yīng)用程序時(shí),您應(yīng)該仔細(xì)考慮性能方面的要求,并且定義合適的性能目標(biāo)。在定義這些目標(biāo)時(shí),請考慮您將如何度量應(yīng)用程序的實(shí)際性能。您的性能度量標(biāo)準(zhǔn)應(yīng)該明確體現(xiàn)應(yīng)用程序的重要性能特征。請努力避免無法準(zhǔn)確度量的模糊或不完整的目標(biāo),例如,“應(yīng)用程序必須快速運(yùn)行”或“應(yīng)用程序必須快速加載”。您需要了解應(yīng)用程序的性能和可伸縮性目標(biāo),以便您可以設(shè)法滿足這些目標(biāo)并且圍繞它們來規(guī)劃您的測試。請確保您的目標(biāo)是可度量的和可驗(yàn)證的。

    定義良好的性能度量標(biāo)準(zhǔn)使您可以準(zhǔn)確跟蹤應(yīng)用程序的性能,以便您可以確定應(yīng)用程序是否能夠滿足它的性能目標(biāo)。這些度量標(biāo)準(zhǔn)應(yīng)該包括在應(yīng)用程序測試計(jì)劃中,以便可以在應(yīng)用程序的測試階段度量它們。

    本節(jié)重點(diǎn)討論與智能客戶端應(yīng)用程序相關(guān)的特定性能目標(biāo)的定義。如果您還要設(shè)計(jì)和生成客戶端應(yīng)用程序?qū)⑾牡木W(wǎng)絡(luò)服務(wù),則您還需要為這些服務(wù)定義適當(dāng)?shù)男阅苣繕?biāo)。在此情況下,您應(yīng)該確保考慮整個(gè)系統(tǒng)的性能要求,以及應(yīng)用程序各個(gè)部分的性能與其他部分以及整個(gè)系統(tǒng)之間存在怎樣的關(guān)系。

    考慮用戶的觀點(diǎn)

    當(dāng)您為智能客戶端應(yīng)用程序確定合適的性能目標(biāo)時(shí),您應(yīng)該仔細(xì)考慮用戶的觀點(diǎn)。對于智能客戶端應(yīng)用程序而言,性能與可用性和用戶感受有關(guān)。例如,只要用戶能夠繼續(xù)工作并且獲得有關(guān)操作進(jìn)度的足夠反饋,用戶就可以接受漫長的操作。

    在確定要求時(shí),將應(yīng)用程序的功能分解為多個(gè)使用情景或使用案例通常是有用的。您應(yīng)該識(shí)別對于實(shí)現(xiàn)特定性能目標(biāo)而言關(guān)鍵且必需的使用案例和情景。應(yīng)該將許多使用案例所共有且經(jīng)常執(zhí)行的任務(wù)設(shè)計(jì)得具有較高性能。同樣,如果任務(wù)要求用戶全神貫注并且不允許用戶從其切換以執(zhí)行其他任務(wù),則需要提供優(yōu)化的且有效的用戶體驗(yàn)。如果任務(wù)不太經(jīng)常使用且不會(huì)阻止用戶執(zhí)行其他任務(wù),則可能無須進(jìn)行大量調(diào)整。

    對于您識(shí)別的每個(gè)性能敏感型任務(wù),您都應(yīng)該精確地定義用戶的操作以及應(yīng)用程序的響應(yīng)方式。您還應(yīng)該確定每個(gè)任務(wù)使用的網(wǎng)絡(luò)和客戶端資源或組件。該信息將影響性能目標(biāo),并且將驅(qū)動(dòng)對性能進(jìn)行度量的測試。

    可用性研究提供了非常有價(jià)值的信息源,并且可能大大影響性能目標(biāo)的定義。正式的可用性研究在確定用戶如何執(zhí)行他們的工作、哪些使用情景是共有的以及哪些不是共有的、用戶經(jīng)常執(zhí)行哪些任務(wù)以及從性能觀點(diǎn)看來應(yīng)用程序的哪些特征是重要的等方面可能非常有用。如果您要生成新的應(yīng)用程序,您應(yīng)該考慮提供應(yīng)用程序的原型或模型,以便可以執(zhí)行基本的可用性測試。

    考慮應(yīng)用程序操作環(huán)境

    對應(yīng)用程序的操作環(huán)境進(jìn)行評(píng)估是很重要的,因?yàn)檫@可能對應(yīng)用程序施加必須在您制定的性能目標(biāo)中予以反映的約束。

    位于網(wǎng)絡(luò)上的服務(wù)可能對您的應(yīng)用程序施加性能約束。例如,您可能需要與您無法控制的 Web 服務(wù)進(jìn)行交互。在這種情況下,需要確定該服務(wù)的性能,并且確定這是否將對客戶端應(yīng)用程序的性能產(chǎn)生影響。

    您還應(yīng)該確定任何相關(guān)服務(wù)和組件的性能如何隨著時(shí)間的變化而變化。某些系統(tǒng)會(huì)經(jīng)受相當(dāng)穩(wěn)定的使用,而其他系統(tǒng)則會(huì)在一天或一周的特定時(shí)間經(jīng)受變動(dòng)極大的使用。這些區(qū)別可能在關(guān)鍵時(shí)間對應(yīng)用程序的性能造成不利影響。例如,提供應(yīng)用程序部署和更新服務(wù)的服務(wù)可能會(huì)在星期一早上 9 點(diǎn)緩慢響應(yīng),因?yàn)樗杏脩舳荚诖藭r(shí)升級(jí)到應(yīng)用程序的最新版本。

    另外,還需要準(zhǔn)確地對所有相關(guān)系統(tǒng)和組件的性能進(jìn)行建模,以便可以在嚴(yán)格模擬應(yīng)用程序的實(shí)際部署環(huán)境的環(huán)境中測試您的應(yīng)用程序。對于每個(gè)系統(tǒng),您都應(yīng)該確定性能概況以及最低、平均和最高性能特征。然后,您可以在定義應(yīng)用程序的性能要求時(shí)根據(jù)需要使用該數(shù)據(jù)。

    您還應(yīng)該仔細(xì)考慮用于運(yùn)行應(yīng)用程序的硬件。您將需要確定在處理器、內(nèi)存、圖形功能等方面的目標(biāo)硬件配置,或者至少確定一個(gè)如果得不到滿足則無法保證性能的最低配置。

    通常,應(yīng)用程序的業(yè)務(wù)操作環(huán)境將規(guī)定一些更為苛刻的性能要求。例如,執(zhí)行實(shí)時(shí)股票交易的應(yīng)用程序?qū)⑿枰獔?zhí)行這些交易并及時(shí)顯示所有相關(guān)數(shù)據(jù)。

    性能調(diào)整過程

    對應(yīng)用程序進(jìn)行性能調(diào)整是一個(gè)迭代過程。該過程由一些重復(fù)執(zhí)行直至應(yīng)用程序滿足其性能目標(biāo)的階段組成。(請參見 8.2。)

    chapter8_f02

    8.2:性能調(diào)整過程

    正如 8.2 所闡明的,性能調(diào)整要求您完成下列過程:

    ?

    建立基準(zhǔn)。在您開始針對性能調(diào)整應(yīng)用程序時(shí),您必須具有與性能目標(biāo)、目標(biāo)和度量標(biāo)準(zhǔn)有關(guān)的定義良好的基準(zhǔn)。這可能包括應(yīng)用程序工作集大小、加載數(shù)據(jù)(例如,目錄)的時(shí)間、事務(wù)持續(xù)時(shí)間等等。

    ?

    收集數(shù)據(jù)。您將需要通過針對您已經(jīng)定義的性能目標(biāo)度量應(yīng)用程序的性能,來對應(yīng)用程序性能進(jìn)行評(píng)價(jià)。性能目標(biāo)應(yīng)該體現(xiàn)特定的且可度量的度量標(biāo)準(zhǔn),以使您可以在任何時(shí)刻量化應(yīng)用程序的性能。要使您可以收集性能數(shù)據(jù),您可能必須對應(yīng)用程序進(jìn)行規(guī)范,以便可以發(fā)布和收集必需的性能數(shù)據(jù)。下一節(jié)將詳細(xì)討論您可以用來完成這一工作的一些選項(xiàng)。

    ?

    分析結(jié)果。在收集應(yīng)用程序的性能數(shù)據(jù)之后,您將能夠通過確定哪些應(yīng)用程序功能要求最多的關(guān)注,來區(qū)分性能調(diào)整工作的輕重緩急。此外,您可以使用該數(shù)據(jù)來確定任何性能瓶頸的位置。通常,您將只能夠通過收集更詳細(xì)的性能數(shù)據(jù)來確定瓶頸的確切位置:例如,通過使用應(yīng)用程序規(guī)范。性能分析工具可能幫助您識(shí)別瓶頸。

    ?

    調(diào)整應(yīng)用程序。在已經(jīng)識(shí)別瓶頸之后,您可能需要修改應(yīng)用程序或其配置,以便嘗試解決問題。您應(yīng)該致力于將更改降低至最低限度,以便可以確定更改對應(yīng)用程序性能的影響。如果您同時(shí)進(jìn)行多項(xiàng)更改,可能難以確定每項(xiàng)更改對應(yīng)用程序的總體性能的影響。

    ?

    測試和度量。在更改應(yīng)用程序或其配置之后,您應(yīng)該再次測試它以確定更改具有的效果,并且使新的性能數(shù)據(jù)得以收集。性能工作通常要求進(jìn)行體系結(jié)構(gòu)或其他具有較高影響的更改,因此徹底的測試是很關(guān)鍵的。您的應(yīng)用程序測試計(jì)劃應(yīng)該針對預(yù)料到的所有情況,在配置了適當(dāng)硬件和軟件的客戶計(jì)算機(jī)上演習(xí)應(yīng)用程序所實(shí)現(xiàn)的完整范圍的功能。如果您的應(yīng)用程序使用網(wǎng)絡(luò)資源,則應(yīng)該加載這些資源,以便您可以獲得有關(guān)應(yīng)用程序在此類環(huán)境中所具有的性能的準(zhǔn)確度量。

    上述過程將使您可以通過針對特定目標(biāo)度量應(yīng)用程序的總體性能,來重點(diǎn)解決特定的性能問題。

    性能工具

    您可以使用許多工具來幫助您收集和分析應(yīng)用程序的性能數(shù)據(jù)。本節(jié)中介紹的每種工具都具有不同的功能,您可以使用這些功能來度量、分析和查找應(yīng)用程序中的性能瓶頸。

    除了這里介紹的工具以外,您還可以使用其他一些選項(xiàng)和第三方工具。有關(guān)其他日志記錄和異常管理選項(xiàng)的說明,請參閱Exception Management Architecture Guide,網(wǎng)址為:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/exceptdotnet.asp

    在決定哪些工具最適合您的需要之前,您應(yīng)該仔細(xì)考慮您的確切要求。

    使用性能日志和警報(bào)

    性能日志和警報(bào)是作為 Windows 操作系統(tǒng)的一部分發(fā)行的一種管理性能監(jiān)控工具。它依靠由各種 Windows 組件、子系統(tǒng)和應(yīng)用程序發(fā)布的性能計(jì)數(shù)器,使您可以跟蹤資源使用情況以及針對時(shí)間以圖形方式繪制它們。

    您可以使用 Performance Logs and Alerts 來監(jiān)控標(biāo)準(zhǔn)的性能計(jì)數(shù)器(例如,內(nèi)存使用情況或處理器使用情況),或者您可以定義您自己的自定義計(jì)數(shù)器來監(jiān)控應(yīng)用程序特定的活動(dòng)。

    .NET CLR 提供了許多有用的性能計(jì)數(shù)器,它們使您可以洞察應(yīng)用程序性能的好壞。關(guān)系比較大的一些性能對象是:

    ?

    .NET CLR 內(nèi)存。提供有關(guān)托管 .NET 應(yīng)用程序內(nèi)存使用情況的數(shù)據(jù),包括應(yīng)用程序正在使用的內(nèi)存數(shù)量以及對未使用的對象進(jìn)行垃圾回收所花費(fèi)的時(shí)間。

    ?

    .NET CLR 加載。提供有關(guān)應(yīng)用程序正在使用的類和應(yīng)用程序域的數(shù)量的數(shù)據(jù),并且提供有關(guān)它們的加載和卸載速率的數(shù)據(jù)。

    ?

    .NET CLR 鎖和線程。提供與應(yīng)用程序內(nèi)使用的線程有關(guān)的性能數(shù)據(jù),包括線程個(gè)數(shù)以及試圖同時(shí)對受保護(hù)的資源進(jìn)行訪問的線程之間的爭用率。

    ?

    .NET CLR 網(wǎng)絡(luò)。提供與通過網(wǎng)絡(luò)發(fā)送和接收數(shù)據(jù)有關(guān)的性能計(jì)數(shù)器,包括每秒發(fā)送和接收的字節(jié)數(shù)以及活動(dòng)連接的個(gè)數(shù)。

    ?

    .NET CLR 異常。提供有關(guān)應(yīng)用程序所引發(fā)和捕獲的異常個(gè)數(shù)的報(bào)告。

    有關(guān)上述計(jì)數(shù)器、它們的閾值、要度量的內(nèi)容以及如何度量它們的詳細(xì)信息,請參閱 Improving .NET Application Performance and Scalability 的第 15 章“Measuring .NET Application Performance”中的“CLR and Managed Code”部分,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt15.asp

    您的應(yīng)用程序還可以提供您可以通過使用性能日志和警報(bào)輕松監(jiān)控的、應(yīng)用程序特定的性能計(jì)數(shù)器。您可以像以下示例所顯示的那樣,定義自定義性能計(jì)數(shù)器:

    [C#]

    PerformanceCounter counter = new PerformanceCounter( "Category", 
                "CounterName", false ); 
    

    [Visual Basic .NET]

    Dim counter As New PerformanceCounter("Category", "CounterName", False) 
    

    在創(chuàng)建性能計(jì)數(shù)器對象之后,您可以為您的自定義性能計(jì)數(shù)器指定類別,并將所有相關(guān)計(jì)數(shù)器保存在一起。PerformanceCounter 類在 System.Diagnostics 命名空間中定義,該命名空間中還定義了其他一些可用于讀取和定義性能計(jì)數(shù)器和類別的類。有關(guān)創(chuàng)建自定義性能計(jì)數(shù)器的詳細(xì)信息,請參閱知識(shí)庫中編號(hào)為 317679 的文章“How to create and make changes to a custom counter for the Windows Performance Monitor by using Visual Basic .NET”,網(wǎng)址為:http://support.microsoft.com/default.aspx?scid=kb;en-us;317679

    要注冊性能計(jì)數(shù)器,您必須首先注冊該類別。您必須具有足夠的權(quán)限才能注冊性能計(jì)數(shù)器類別(它可能影響您部署應(yīng)用程序的方式)。

    規(guī)范

    您可以使用許多工具和技術(shù)來幫助您對應(yīng)用程序進(jìn)行規(guī)范,并且生成度量應(yīng)用程序性能所需的信息。這些工具和技術(shù)包括:

    ?

    Event Tracing for Windows (ETW)。該 ETW 子系統(tǒng)提供了一種系統(tǒng)開銷較低(與性能日志和警報(bào)相比)的手段,用以監(jiān)控具有負(fù)載的系統(tǒng)的性能。這主要用于必須頻繁記錄事件、錯(cuò)誤、警告或?qū)徍说姆?wù)器應(yīng)用程序。有關(guān)詳細(xì)信息,請參閱 Microsoft Platform SDK 中的“Event Tracing”,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/event_tracing.asp

    ?

    Enterprise Instrumentation Framework (EIF)。EIF 是一種可擴(kuò)展且可配置的框架,您可以使用它來對智能客戶端應(yīng)用程序進(jìn)行規(guī)劃。它提供了一種可擴(kuò)展的事件架構(gòu)和統(tǒng)一的 API — 它使用 Windows 中內(nèi)置的現(xiàn)有事件、日志記錄和跟蹤機(jī)制,包括 Windows Management Instrumentation (WMI)、Windows Event Log 和 Windows Event Tracing。它大大簡化了發(fā)布應(yīng)用程序事件所需的編碼。如果您計(jì)劃使用 EIF,則需要通過使用 EIF .msi 在客戶計(jì)算機(jī)上安裝 EIF。如果您要在智能客戶端應(yīng)用程序中使用 EIF,則需要在決定應(yīng)用程序的部署方式時(shí)考慮這一要求。有關(guān)詳細(xì)信息,請參閱“How To:Use EIF”,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenethowto14.asp

    ?

    Logging Application Block。Logging Application Block 提供了可擴(kuò)展且可重用的代碼組件,以幫助您生成規(guī)范化的應(yīng)用程序。它建立在 EIF 的功能基礎(chǔ)之上,以提供某些功能,例如,針對事件架構(gòu)的增強(qiáng)功能、多個(gè)日志級(jí)別、附加的事件接收等等。有關(guān)詳細(xì)信息,請參閱“Logging Application Block”,網(wǎng)址為“http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/Logging.asp

    ?

    Windows Management Instrumentation (WMI)。WMI 組件是 Windows 操作系統(tǒng)的一部分,并且提供了用于訪問企業(yè)中的管理信息和控件的編程接口。系統(tǒng)管理員常用它來自動(dòng)完成管理任務(wù)(通過使用調(diào)用 WMI 組件的腳本)。有關(guān)詳細(xì)信息,請參閱 Windows Management Information,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_start_page.asp

    ?

    調(diào)試和跟蹤類。.NET Framework 在 System.Diagnosis 下提供了 DebugTrace 類來對代碼進(jìn)行規(guī)范。Debug 類主要用于打印調(diào)試信息以及檢查是否有斷言。Trace 類使您可以對發(fā)布版本進(jìn)行規(guī)范,以便在運(yùn)行時(shí)監(jiān)控應(yīng)用程序的完好狀況。在 Visual Studio .NET 中,默認(rèn)情況下啟用跟蹤。在使用命令行版本時(shí),您必須為編譯器添加 /d:Trace 標(biāo)志,或者在 Visual C# .NET 源代碼中添加 #define TRACE,以便啟用跟蹤。對于 Visual Basic .NET 源代碼,您必須為命令行編譯器添加 /d:TRACE=True。有關(guān)詳細(xì)信息,請參閱知識(shí)庫中編號(hào)為 815788 的文章“HOW TO:Trace and Debug in Visual C# .NET”,網(wǎng)址為:http://support.microsoft.com/default.aspx?scid=kb;en-us;815788

    CLR Profiler

    CLR Profiler 是 Microsoft 提供的一種內(nèi)存分析工具,并且可以從 MSDN 下載。它使您能夠查看應(yīng)用程序進(jìn)程的托管堆以及調(diào)查垃圾回收器的行為。使用該工具,您可以獲取有關(guān)應(yīng)用程序的執(zhí)行、內(nèi)存分配和內(nèi)存消耗的有用信息。這些信息可以幫助您了解應(yīng)用程序的內(nèi)存使用方式以及如何優(yōu)化應(yīng)用程序的內(nèi)存使用情況。

    CLR Profiler 可從 http://msdn.microsoft.com/netframework/downloads/tools/default.aspx 獲得。有關(guān)如何使用 CLR Profiler 工具的詳細(xì)信息,另請參閱“How to use CLR Profiler”,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenethowto13.asp?frame=true

    CLR Profiler 在日志文件中記錄內(nèi)存消耗和垃圾回收器行為信息。然后,您可以使用一些不同的圖形視圖,通過 CLR Profiler 來分析該數(shù)據(jù)。一些比較重要的視圖是:

    ?

    Allocation Graph。顯示有關(guān)對象分配方式的調(diào)用堆棧。您可以使用該視圖來查看方法進(jìn)行的每個(gè)分配的系統(tǒng)開銷,隔離您不希望發(fā)生的分配,以及查看方法可能進(jìn)行的過度分配。

    ?

    Assembly, Module, Function, and Class Graph。顯示哪些方法造成了哪些程序集、函數(shù)、模塊或類的加載。

    ?

    Call Graph。使您可以查看哪些方法調(diào)用了其他哪些方法以及相應(yīng)的調(diào)用頻率。您可以使用該圖表來確定庫調(diào)用的系統(tǒng)開銷,以及調(diào)用了哪些方法或?qū)μ囟ǚ椒ㄟM(jìn)行了多少個(gè)調(diào)用。

    ?

    Time Line。提供了有關(guān)應(yīng)用程序執(zhí)行的基于文本的、按時(shí)間順序的層次結(jié)構(gòu)視圖。使用該視圖可以查看分配了哪些類型以及這些類型的大小。您還可以使用該視圖查看方法調(diào)用使得哪些程序集被加載,并且分析您不希望發(fā)生的分配。您可以分析完成器的使用情況,并且識(shí)別尚未實(shí)現(xiàn)或調(diào)用 CloseDispose 從而導(dǎo)致瓶頸的方法。

    您可以使用 CLR Profiler.exe 來識(shí)別和隔離與垃圾回收有關(guān)的問題。這包括內(nèi)存消耗問題(例如,過度或未知的分配、內(nèi)存泄漏、生存期很長的對象)以及在執(zhí)行垃圾回收時(shí)花費(fèi)的時(shí)間的百分比。

    有關(guān)如何使用 CLR Profiler 工具的詳細(xì)信息,請參閱“Improving .NET Application Performance and Scalability”,網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenethowto13.asp?frame=true

    返回頁首返回頁首

    小結(jié)

    要完全實(shí)現(xiàn)智能客戶端應(yīng)用程序的潛能,您需要在應(yīng)用程序的設(shè)計(jì)階段仔細(xì)考慮性能問題。通過在早期階段解決這些性能問題,您可以在應(yīng)用程序設(shè)計(jì)過程中控制成本,并減小在開發(fā)周期的后期陷入性能問題的可能性。

    本章分析了許多不同的技術(shù),您可以在規(guī)劃和設(shè)計(jì)智能客戶端應(yīng)用程序時(shí)使用這些技術(shù),以確保優(yōu)化它們的性能。本章還考察了您可以用來確定智能客戶端應(yīng)用程序內(nèi)的性能問題的一些工具和技術(shù)。

    返回頁首返回頁首

    參考資料

    有關(guān)詳細(xì)信息,請參閱以下內(nèi)容:

    ?

    http://msdn.microsoft.com/perf

    ?

    http://www.windowsforms.net/Default.aspx

    ?

    http://msdn.microsoft.com/vstudio/using/understand/perf/

    ?

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/html/netcfimproveformloadperf.asp

    ?

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/highperfmanagedapps.asp

    ?

    http://msdn.microsoft.com/msdnmag/issues/02/08/AdvancedBasics/default.aspx

    ?

    http://msdn.microsoft.com/library/default.asp?url=/msdnmag/issues/04/01/NET/toc.asp?frame=true

    ?

    http://msdn.microsoft.com/library/default.asp?url=/msdnmag/issues/03/02/Multithreading/toc.asp?frame=true

    轉(zhuǎn)到原英文頁面

    posted on 2006-02-10 14:58 TrampEagle 閱讀(508) 評(píng)論(0)  編輯  收藏 所屬分類: 技術(shù)文摘
    主站蜘蛛池模板: 国产小视频免费观看| 日韩av无码免费播放| 亚洲Aⅴ在线无码播放毛片一线天| 亚洲欧洲在线播放| 亚洲精品国产啊女成拍色拍| 亚洲ⅴ国产v天堂a无码二区| 久久久久亚洲av无码尤物| 亚洲国产精品无码av| 久久亚洲国产精品| 久久国产亚洲电影天堂| 久久亚洲国产中v天仙www| 亚洲国产精品热久久| 亚洲资源在线视频| 亚洲伊人久久大香线焦| 亚洲午夜国产精品| 亚洲日韩中文字幕一区| 亚洲国产av玩弄放荡人妇 | 免费看美女让人桶尿口| 男女交性永久免费视频播放| 国产免费无遮挡精品视频 | 日本免费xxxx| 国色精品卡一卡2卡3卡4卡免费| AV免费网址在线观看| 国产男女性潮高清免费网站| 亚洲福利视频一区二区| 中文字幕亚洲乱码熟女一区二区| 久久亚洲国产中v天仙www| 亚洲精品亚洲人成在线观看麻豆 | 亚洲国产精彩中文乱码AV| 亚洲自偷自偷精品| 亚洲中文字幕AV在天堂| 亚洲第一成年网站视频| 一级特黄aaa大片免费看| 国产成人无码区免费网站| 222www在线观看免费| 免费特级黄毛片在线成人观看| 五月天婷亚洲天综合网精品偷| 久久亚洲成a人片| 亚洲日产乱码一二三区别| 一级女人18片毛片免费视频| 免费观看男人吊女人视频|