技巧 9:進程外執行過程以性能換取可靠性
asp 和 MTS/COM+ 兩者都有配置選項,可使您兼顧可靠性和性能。當建立和部署應用程序時,應知道如何兼顧兩者的性能。ASP 選項可以配置 ASP 應用程序,以便以三種方法之一運行。在 IIS 5.0 中,引入了“隔離級”這一術語以說明這些選項。這三個隔離級分別是低級、中級和高級:
低級隔離:這在 IIS 的所有版本中都得到支持,且是最快的。它在 Inetinfo.exe 中運行 ASP,Inetinfo.exe 是主要 IIS 進程。如果 ASP 應用程序崩潰,IIS 也會崩潰。(要在 IIS 4.0 下重新啟動 IIS,Web 站點管理員應使用諸如 InetMon 之類的工具監視站點,如果服務器發生故障,應啟用批處理文件以重新啟動服務器。IIS 5.0 引入了可靠的重新啟動,該方法可使發生故障的服務器自動重新啟動。)
中級隔離:IIS 5.0 引入了這個新的級別,它被稱為進程外級別,因為 ASP 在 IIS 進程之外運行。在中級隔離中,被配置作為中級隔離運行的所有 ASP 應用程序都共享一個進程空間。這就減少了在一台服務器運行多個進程外 ASP 應用程序所需要的進程數量。中級隔離是 IIS 5.0 中的默認隔離級別。
高級隔離:在 IIS 4.0 和 IIS 5.0 中支持這一級別,高級隔離也是進程外的。如果 ASP 崩潰,Web 服務器並不會崩潰。下次 ASP 請求時,ASP 應用程序就會自動重新啟動。在高級隔離中,配置作為高級隔離運行的每個 ASP 應用程序都在其自有進程空間中運行。這樣做可保護 ASP 應用程序彼此之間不相互干擾。其缺點是它要求每個 ASP 應用程序都要有一個單獨的進程。當在一台服務器上必須運行許多應用程序時,系統開銷就會大大增加。
哪個選項最好的呢?在 IIS 4.0 中,進程外運行將顯著降低性能。在 IIS 5.0 中,做了許多改進,將進程外運行 ASP 應用程序所產生的開銷降到最低限度。事實上,在絕大多數測試中,IIS 5.0 中的 ASP 進程外應用程序比 IIS 4.0 中的進程內應用程序運行得更快。不管怎樣,在兩個平台上,進程內(低隔離級)性能最佳。但是,如果訪問率相對較低或最大吞吐量較低,低隔離級的優勢不太明顯。因此,在您每一 Web 服務器每秒鐘需要數百或成千上萬頁面時,才會覺得有必要設置低隔離級。與往常一樣,應對多種配置進行測試,確定您要采取哪一種折衷方案。
注意 當您運行 ASP 進程外應用程序時(中級或高級隔離),它們在 NT4 中的 MTS 和在 Windows 2000 中的 COM+ 中運行。即,在 NT4 中它們在 Mtx.exe 中運行;而在 Windows 2000 中,它們在 DllHost.exe 中運行。您可以在任務管理器中看到這些進程在運行。您還可以看到 IIS 如何為進程外 ASP 應用程序配置 MTS 程序包或 COM+ 應用程運行。您還可以看到 IIS 如何為進程外 ASP 應用程序配置 MTS 程序包或 COM+ 應用程序。
COM 選項
COM 組件也有三種配置選項,雖然與 ASP 選項不完全類似。COM 組件可以是“未配置的”、配置為庫應用程序或配置為服務器應用程序。“未配置的”意思是指組件沒有注冊COM+。組件將在調用程序的進程空間運行,那就是說,它們是“進程內的”。庫應用程序也是進程內的,但使用 COM+ 的服務,包括安全、事務和上下文支持。服務器應用程序被配置為在它們自有的進程空間內運行。
您可以看到未配置的組件比庫應用程序略有一些優勢。庫應用程序比服務器應用程序的性能優點更大。這是因為庫應用程序與 ASP 在同一進程內運行,而服務器應用程序在它們的自有進程內運行。進程間的調用比進程內調用開銷更大。而且,當在進程之間傳遞諸如記錄集之類的數據時,必須在兩個進程之間復制所有的數據。
陷阱!當使用 COM 服務器應用程序時,如果您在 ASP 和 COM 之間傳遞對象,要確保對象執行“按值匯集”或 MBV。執行 MBV 的對象將它們自己從一個進程復制到另一個進程。這比下面一種方法好,采用這種方法時,對象仍在創建者的進程中,另外一個進程反復地調用創建進程以使用該對象。切斷連接的 ADO 記錄集將“按值匯集”,連接的記錄集則不然。Scripting.Dictionary 不執行 MBV,且不在進程之間傳遞。
最後,VB 程序員請注意:MBV 不通過傳遞參數 ByVal 獲得。MBV 由原始的組件作者執行。怎麼辦?
如果讓我們建議一個兼顧性能與可靠性的合理配置,它們應是如下的配置:
在 IIS 4.0 中,使用 ASP 低隔離級別,使用 MTS 服務器程序包。
在 IIS 5.0 上,使用 ASP 的中隔離級,並使用 COM+ 庫應用程序。
這些是非常一般的原則,主機服務公司一般情況下以中或高隔離級運行 ASP,而單用途的 Web 服務器可以以低隔離級運行。衡量各種利弊,並自己決定哪個配置更能符合您的需要。
技巧 10:使用顯式選項
在 .asp 文件中應使用 Option Explicit。此指令放在 .ASP 文件的最上面,它強制開發人員聲明要使用到的所有變量。許多程序員認為這種方法對於調試應用程序很有幫助,因為這種方法避免了鍵錯變量名和誤建新變量的可能性(例如,將 MyXMLString=) 錯寫成 MyXLMString=...。
更重要的一點也許是,聲明的變量比未聲明的變量速度更快。由此,腳本在運行時每次用到未聲明的變量時,按名稱引用它。另一方面,聲明的變量是有順序的,要麼以編譯時間,要麼以運行時間。以後,聲明的變量都按此順序引用。因為 Option Explicit 強制變量聲明,它能確保聲明所有變量,因此訪問的速度也很快。
技巧 11:在子例程和函數中使用局部變量
局部變量是那些在子例程和函數內聲明的變量。在函數或子例程內,局部變量訪問比全局變量訪問更快。局部變量的使用也會使代碼更清晰,因此應盡量使用局部變量。
技巧 12:將經常使用的數據復制到腳本變量中
當訪問 ASP 中的 COM 對象時,應將經常使用的對象數據復制到腳本變量中。這樣做可減少 COM 方法調用,因為 COM 方法調用與訪問腳本變量相比,開銷相對較大。當訪問Collection 和 Dictionary 對象時,這種技術也會減少開銷很大的查找。
一般來說,如果您打算不止一次訪問對象數據,那麼就應將數據放到腳本變量中。這種優化的主要目標是 Request 變量(Form 和 QueryString 變量)。例如,您的站點可傳遞一個名為 UserID 的 QueryString 變量。假設此 UserID 在特定頁面上被引用 12 次。可以無須調用 Request(?UserID?) 12 次,而是在 ASP 頁面最上面將 UserID 指派到。可以無須調用 Request(?UserID?) 12 次,而是在 ASP 頁面最上面將 UserID 指派到一個變量。然後在該頁面自始至終使用該變量。這樣就省去了 11 次 COM 方法調用。實際上,訪問 COM 屬性或方法的開銷並沒有那麼大。
技巧 13:避免重新確定數組的維數
應盡量避免 Redim 數組。就性能而言,如果計算機的物理內存大小有限,最好將數組的初始維數設置為其最不利的情況 - 或將維數設置為其最佳的情況,然後再按需要重新確定維數。這並非意味著,如果知道您不需要內存時,就隨便分配幾兆字節的內存。
下面的代碼給您顯示使用 Dim 和 Redim 不當的情形。
<%
Dim MyArray()
Redim MyArray(2)
MyArray(0) = ?hello?
MyArray(1) = ?good-bye?
MyArray(2) = ?farewell?
...
' some other code where you end up needing more space happens, then ...
Redim PReserve MyArray(5)
MyArray(3) = ?more stuff?
MyArray(4) = ?even more stuff?
MyArray(5) = ?yet more stuff?
MyArray(5) = ?yet more stuff?
%>
最好一開始就將數組的初始大小 Dim 正確(在本例中,是 5)比 Redim 數組使其更大好得多。您可能浪費一些內存(如果您沒有使用所有的元素),但獲得的好處是速度變得更快。
技巧 14:使用響應緩沖
您可以通過啟用“響應緩沖”,將要輸出的一整頁緩沖起來。這樣就將寫到浏覽器的量減到最少,從而改善總體性能。每個寫操作都會產生很大的系統開銷(在 IIS 中以及在通過網絡發送的數據量方面),因此寫操作越少越好。由於其啟動慢且使用 Nagling 算法(用來減輕網絡塞車情況),TCP/IP 在發送一些大的數據塊時比必須發送許多小的數據塊時的效率高得多。
有兩個方法啟用響應緩沖。
第一種,您可以使用 Internet Services Manager 為整個應用程序啟用響應緩沖。我們建議采用這種方法,在 IIS 4.0 和 IIS 5.0 中默認為新的ASP 應用程序啟用響應緩沖。
第二種,可以在每個 ASP 頁面的接近頂端的地方加入下面的代碼行,從而啟用響應緩沖:
<% Response.Buffer = True %>
此代碼行必須在任何響應數據被寫到浏覽器之前執行(即,在任何 Html 出現在 ASP 腳本之前以及在使用 Response.Cookies 集合設置任何 CookIEs 之前)。一般來說,最好為整個應用程序啟用響應緩沖。這樣,您就不必在每個頁面最上面寫入上述的代碼行。
Response.Flush
關於響應緩沖有一個常見的抱怨,就是用戶感覺到 ASP 頁面的響應速度很慢(即使整個響應時間得到改進),因為他們必須等到整個頁面生成,然後他們才能看到東西。對於響應時間得到改進),因為他們必須等到整個頁面生成,然後他們才能看到東西。對於運行時間長的頁面,您可以設置 Response.Buffer = False,禁用響應緩沖。但是,一個更好的策略是利用 Response.Flush 方法。這種方法將 ASP 轉換的所有 Html 送到浏覽器。例如,在轉換 1,000 行的表的前 100 行之後,ASP 可以調用 Response.Flush,強制將轉換的結果送到浏覽器,這樣可使用戶在其余的行准備好之前看到頭 100 行。這種技術可以將響應緩沖與浏覽器逐漸顯示數據完美地結合在一起。(注意在上面的 1,000 行表的舉例中,許多浏覽器在它們看到關閉 </table>標記之前不會開始顯示表。檢查您的目標浏覽器是否支持。為避免這種情況,將表分成多個具有較少行的表,並在每個表之後調用 Response.Flush。較新版本的 Internet Explorer在表完全下載之前就開始顯示表,如果您指定表列寬,顯示速度就會特別快,這樣做可避免強制 Internet Explorer 通過測量每個單元格的內容寬度來計算列寬。)另一個關於響應緩沖的常見的抱怨是,當產生非常大的頁面時,將占用許多服務器內存。撇開產生大頁面的方法不談,這種問題也可通過巧妙使用 Response.Flush 來加以解決。
技巧 15:批處理內嵌腳本和 Response.Write 語句
VBScript 語法 <% = expression %>將“expression”的值寫到 ASP 輸出流中。如果響應緩沖未啟用,那麼執行其中的每一條語句,都會以許多小的數據包通過網絡將數據寫到浏覽器中。這樣速度很慢。而且穿插執行少量的腳本和 HTML,將引起腳本引擎和Html 之間的切換,從而降低性能。因此,使用下面的技巧:使用 Response.Write 調用代替捆綁緊密的內嵌表達式。當禁用響應緩沖時,這一技巧的效果特別大。最好啟用響應緩沖,然後看批處理 Response.Write 是否有助於提高性能。
技巧 16:如果頁面需要很長時間才能完成,那麼執行前使用 Response.IsClIEntConnected
如果用戶性急,他們可能會在您開始執行他們的請求之前,就會放棄 ASP 頁面。如果他們單擊刷新或移到服務器上的另一個頁面,在 ASP 請求隊列的末尾就有一個新的請求等候,在隊列的中間有一個斷開連接的請求。當服務器的負載很高時(因此請求隊列就會很長,響應時間也會相應地變長),就會經常發生這種情況,這樣只能使情況變得更糟。如果用戶不再連接,執行 ASP 頁面(特別是慢的、大的 ASP 頁面)已沒有任何意義
。您可以使用 Response.IsClIEntConnected 屬性檢查這一情況。如果它返回 False,則應調用 Response.End 並放棄頁的其余部分。事實上,IIS 5.0 已將這一做法編為程序 - 每當 ASP 即將執行新請求時,它就會檢查請求在隊列中已等候了多長時間。如果已經在那裡等候了多於 3 秒鐘,ASP 將檢查客戶機是否仍處於連接狀態,如果沒有連接已經在那裡等候了多於 3 秒鐘,ASP 將檢查客戶機是否仍處於連接狀態,如果沒有連接,就立即終止請求。您可以在配置數據庫中使用 ASPQueueConnectionTestTime 設置將超時時間由 3 秒調整為其它值。如果頁面要花很長時間才能執行完,也可以不時地檢查 Response.IsClIEntConnected。當啟用了響應緩沖時,最好不時地執行 Response.Flush,以用戶知道,正在發生什麼事。
注意 在 IIS 4.0 上,除非先執行了 Response.Write,否則 Response.IsClIEntConnected 就不能正常工作。如果啟用了緩沖,您也必須執行 Response.Flush。在 IIS 5.0上,卻沒有必要這樣做,- Response.IsClientConnected 工作正常。在任何情況下,Response.IsClIEntConnected 都會有一些開銷,因此只有在一個操作至少要花(比方說) 500 毫秒(如果您想維持每秒鐘數十頁的吞吐量,這是一個很長的時間)才使用它。
經驗表明,不要每次重復執行緊密循環時都調用它,如顯示表的許多行時 - 每隔二十或五十行調用一次可能比較合適。
技巧 17:使用 <OBJECT>標記例示對象
如果要引用不在所有代碼路徑(特別是服務器或應用程序作用域的對象)中使用的對象,使用 Global.asa 中 <object runat=server id=objname> 標記聲明它們,而不使用Server.CreateObject 方法。Server.CreateObject 能立即創建對象。如果以後不再使用該對象,您就浪費了資源。<object id=objname> 標記聲明 objname,但在其方法或屬性第一次使用以前,不會創建 objname。這又是一個惰性計算的例子。
技巧 18:對於 ADO 和其它組件使用 TypeLib 聲明
當使用 ADO 時,開發人員經常加入 adovbs.txt,以訪問 ADO 的各種常量。在要使用常量的每個頁面中必須包含此文件。此常量文件相當大,給每個 ASP 頁面的編譯時間和腳技巧 18:對於 ADO 和其它組件使用 TypeLib 聲明本大小增加了許多系統開銷。IIS 5.0 引入了綁定到組件類型庫的功能。這可使您引用類型庫一次,並將其用在每個ASP 頁面上。每個頁面不會產生編譯常量文件的開銷,且組件開發人員不必建立VBScript#_include 文件以在 ASP 上使用。要訪問 ADO TypeLib,將下面一條語句放在 Global.asa 中。
<!-- METADATA NAME=?Microsoft ActiveX Data Objects 2.5 Library?
TYPE=?TypeLib? UUID=?{00000205-0000-0010-8000-00AA006D2EA4}? -->
或
<!-- METADATA TYPE=?TypeLib?
FILE=?C:\Program Files\Common Files\system\ado\msado15.dll? -->