程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> ASP編程 >> ASP技巧 >> 改進性能和樣式的 25+ ASP 技巧(2)

改進性能和樣式的 25+ ASP 技巧(2)

編輯:ASP技巧

技巧 6:妙用 session 對象

在肯定了在 applications 和 Sessions 中緩存的優點之後,我們建議您避免使用 Session 對象。下面將會談到,當用於忙碌站點時,Sessions 有幾個缺點。所謂忙碌,通常是指站點每秒請求數百頁或同時有數千個用戶。該技巧對於必須進行水平擴展的站點,即那些利用多個服務器來適應負載或執行容錯功能的站點來說,更加重要。對於較小的站點,如 intranet 站點,Sessions 的便利,與開銷相比也是值得的。

為了翻新,ASP 自動為每個訪問 Web 服務器的用戶創建一個 Session。每個 Session 有大約 10 KB 內存開銷(在存儲在 Session 中的任何數據中是最高的),並使所有的請求都慢了一點。Session 一直保持活動狀態,直到達到可配置的超時(通常 20 分鐘)為止。

Session 最大的問題不是性能而是可伸縮性。Session 不能跨越 Web 服務器;一旦在一個服務器上創建了 Session,它的數據就保持在那裡。這意味著,如果您在 Web 領域中使用 Sessions,您將不得不為每個用戶的請求設計一種策略,以便始終將這些請求引向用戶的 Session 所在的服務器。這被稱為將用戶“粘”到 Web 服務器上。術語“粘性會話”即來源於此。由於 Session 沒有保持到磁盤上,所以,當 Web 服務器崩潰時,被“粘住”的用戶將丟失他們的 Sessions 狀態。

用於實施粘性會話的策略包括硬件和軟件解決方案。如 Windows 2000 Advanced Server 中的網絡負載平衡解決方案和 Cisco 公司的“本地指向器”解決方案可以實施粘性會話,但以犧牲一些可伸縮性為代價。這些解決方案並不完美。我們不主張您現在全盤推翻您的軟件解決方案(我們過去常用 ISAPI 篩選器和 URL 矯直對方案進行檢查)。

Application 對象也不能跨越服務器;如果您需要在 Web 領域內共享並更新 Application 數據,則需要使用後端數據庫。但只讀的 Application 數據在 Web 領域中仍然有用。

如果只是為了增加正常運行時間(用於處理故障轉移和服務器維護),大多數執行重要任務的站點將需要部署至少兩台 Web 服務器。所以,在設計執行重要任務的應用程序時,您將需要實施“粘性會話”,或者簡單地避開 Sessions 以及其他任何在單個 Web 服務器上存儲用戶狀態的狀態管理技術。

如果當前沒有使用 Sessions,請確保將它們關閉。可以通過“Internet 服務管理器”(請參閱 ISM 文檔)來為應用程序執行該操作。如果決定使用 Sessions,可以采取幾個方法來將對性能的影響降低到最小。

可以將不需要 Sessions 的內容(如“幫助”屏幕、訪問者區域等)移動到關閉了 Sessions 的、單獨的 ASP 應用程序中。可以逐頁提示 ASP:在給定的頁中您不需要 Session 對象;使用位於 ASP 頁頂端的如下指令:

<% @EnableSessionState=False %>

使用該指令的一個很好的原因是,Session 給框架集帶來了有趣的問題。ASP 保證任何時候只執行一個來自 Session 的請求。這樣可以確保如果浏覽器為一個用戶請求了多個頁時,在每一時刻只有一個 ASP 請求將進入 Session;這就避免了在訪問 Session 對象時出現多線程問題。遺憾的是,結果,框架集中的所有頁均被以串行化方式繪制,一個接一個地,而不是同時地。這樣,用戶可能不得不等待很長時間才能得到所有框架內容。這意味著:如果某些框架頁不信任 Session,一定要使用 @EnableSessionState=False 指令告訴 ASP。

作為使用 Session 對象的替代方式,有很多方法可以用來管理 Session 狀態。對於狀態數量較小的情況(不到 4 KB),通常建議使用 CookIEs、QueryString 變量和隱藏形式的變量。對於較大數量的數據,如購物推車,則使用後端數據庫是最合適的選擇。關於在 Web 服務器領域中的狀態管理技術已經有很多資料。詳細信息,請參閱 會話狀態(英文)。

技巧 7:在 COM 對象中封裝代碼

如果您有很多 VBScript 或 JScript,那麼您可以通過把代碼移動到已編譯的 COM 對象來經常改進它們的性能。已編譯的代碼通常比被解釋代碼運行得更快。已編譯的 COM 對象可以通過“早期綁定”訪問其他 COM 對象,這種調用 COM 對象方法的手段,比腳本所使用的“後期綁定”更有效。

將代碼封裝在 COM 對象種有如下好處(超越性能):

COM 對象是將表達邏輯與業務邏輯分隔開來的好辦法。
COM 對象啟用了代碼重用。
很多開發商發現,用 VB、C++ 或 Visual J++ 書寫的代碼,比 ASP 更容易調試。
COM 對象有一些缺點,包括初始開發時間以及需要不同的編程技巧。需要警告您的是,封裝“少”量的 ASP 可能會導致性能降低,而不是提高。通常,在少量 ASP 代碼封裝到 COM 對象時出現這樣的情況。這時候,創建和調用 COM 對象的開銷,超過了已編譯代碼的好處。至於 ASP 腳本和 COM 對象代碼怎樣合並才能產生最佳性能還有待測試。注意,與 Windows NT(R) 4.0/IIS 4.0 相比,Microsoft 已經在 Windows 2000/IIS 5.0 中極大地提高了腳本和 ADO 性能。這樣,已編譯代碼對 ASP 代碼的性能優勢已經隨著 IIS 5.0 的引入而降低。

有關在 ASP 中使用 COM 對象的優缺點的更多討論,請參閱 ASP 組件准則和用 COM 和 Microsoft Visual Basic 6.0 對分布式應用程序進行編程(英文)。如果您的確部署了 COM 組件,要對它們進行強度測試是非常重要的。實際上,所有 ASP 應用程序都應當作為正式過程進行強度測試。

技巧 8:晚點獲取資源,早點釋放資源

這是個小技巧。通常,最好晚點獲取資源而要早點釋放資源。這些資源包括 COM 對象、文件句柄和其他資源。

ADO 連接和記錄集是這種優化的首要目標。當您使用完記錄集,就是說用它的數據打印完一個表格後,請立即將它釋放,而不是等到頁的末尾。將您的 VBScript 變量設置為 Nothing 是最好的做法。不要讓記錄集簡單地脫離作用域。同時,應當釋放任何有關的 Command 或 Connection 對象。(不要忘了對記錄集或“連接”調用 Close(),在將它們設置為 = Nothing 之前。)這將縮短數據庫必須為您調整資源的時間跨度,並將數據庫連接盡可能快地釋放給連接池。

技巧 9:進程外的執行將犧牲可靠性

ASP 和 MTS/COM+ 都有允許您以可靠性換取性能的配置選項。當建立和部署應用程序時,應當理解這種交換。

ASP 選項

ASP 應用程序可以配置為以三種方式之一運行。在 IIS 5.0 中引入了術語“隔離級”來描述這些選項。三個隔離級值分別是低、中和高:

低級隔離。該隔離級在所有版本的 IIS 中受到支持,並且是最快的。它在主 IIS 進程 Inetinfo.exe 中執行 ASP。如果 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 文件中顯式使用選項 Explicit。置於 .ASP 文件開頭的這一指令,強制開發人員聲明所有要使用的變量。許多開發人員認為這有助於調試應用程序,因為它避免了錯誤鍵入變量名稱而不經意地新建變量(例如,MyXLMString=... 而非 MyXMLString=)。

也許更重要的是,聲明的變量比未聲明的變量快。實際上,腳本運行時,在每次使用未聲明變量時按照名稱引用。而聲明的變量,在編譯或運行時分配了序號。這樣,聲明的變量按照該序號引用。由於選項 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 ' 對 blah 做一次解析
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 編程同樣有效。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved