技巧 8:遲一點獲得資源,早一點釋放資源
技巧 9:進程外執行過程以性能換取可靠性
技巧 10:使用顯式選項
技巧 11:在子例程和函數中使用局部變量
技巧 12:將經常使用的數據復制到腳本變量中
技巧 13:避免重新確定數組的維數
技巧 14:使用響應緩沖
技巧 8:遲一點獲得資源,早一點釋放資源
這裡是一個小技巧供您參考。一般來說,最好遲一點獲得資源,早一點釋放資源。這適用於 COM 對象以及文件句柄和其它資源。
這種優化方法主要用於 ADO 連接和記錄集。當您使用完記錄集,比方說在顯示一個表及其數據之後,應立即釋放它,而不是等到頁面結束時再釋放。將 VBScript 變量設置為 Nothing 是最好的做法。不要讓記錄集超出作用域之外。而且,要釋放任何相關的 Command 或 Connection 對象(在將記錄集或連接設置為 = Nothing 之前,不要忘記調用 Close())。這會縮短數據庫必須為您准備資源的時間,並盡快釋放數據庫到連接池的連接。
技巧 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+ 應用程序。
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 指派到一個變量。然後在該頁面自始至終使用該變量。這樣就省去了 11 次 COM 方法調用。
實際上,訪問 COM 屬性或方法的開銷並沒有那麼大。下面舉一個例子,說明某相當常見的代碼(從語法上講):
Foo.bar.blah.baz = Foo.bar.blah.qaz(1)
If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ' ...
當此代碼運行時,下面是發生的情況:
變量 Foo 被解析為全局對象。
變量 bar 被解析為 Foo 的成員。這實際就是一次 COM 方法調用。
變量 blah 被解析為 Foo.bar 的成員。這又是一次 COM 方法調用。
變量 qaz 被解析為 foo.bar.blah 的成員。沒有錯,這還是一次 COM 方法調用。
調用 Foo.bar.blah.quaz(1)。再一次 COM 方法調用。懂了嗎?
再次執行步驟 1 至步驟 3 以解析 baz。系統並不知道調用 qaz 是否改變對象模型,因此必須再次執行步驟 1 至 3 以解析 baz。
將 baz 解析為 Foo.bar.blah 的成員。賦予屬性。
再次執行步驟 1 至步驟 3 以解析 zaq。
再次執行步驟 1 至步驟 3 以解析 abc。
正如您可看到的,效率相當差(且慢)。以 VBScript 寫此代碼的快速方法是:
Set myobj = Foo.bar.blah ' do the resolution of blah ONCE
Myobj.baz = myobj.qaz(1)
If Myobj.zaq = Myobj.abc Then '...
如果您使用 VBScript 5.0 或更高版本,您可以使用 With 語句寫此代碼:
With Foo.bar.blah
.baz = .qaz(1)
If .zaq = .abc Then '...
...
End With
注意此技巧也適用於 VB 程序設計。
技巧 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?
%>
最好一開始就將數組的初始大小 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 來加以解決。