提高ASP效能的22個技巧(一)

來源:互聯網
上載者:User
技巧|效能

  技巧1:將常用資料在Web伺服器端緩衝起來 

  大部分的ASP頁面都要從後台資料庫中提取資料,然後將資料用HTML方式表現出來。 
不管你的資料庫多麼快,從記憶體中提取資料總比從後台資料庫中提取快;從本地硬碟中讀取資料通常也比從資料庫中快。因此,你可以通過在Web伺服器端快取資料來提高效能。 

  緩衝是個典型的以空間換取時間的交易。如果你正確的緩衝了資料,效能可能會突飛猛進。要想一個緩衝能真正發揮效益,必須緩衝那些常用和計算複雜的資料。裝滿到期資料的緩衝區只能浪費記憶體。 

  不經常變化的資料也是緩衝的一個良好候選者,因為你可以不用關心同資料庫中的資料保持同步。下拉式清單方塊、參考資料表、小段DHTML代碼,XML字串、功能表項目和網站組態變數(包括資料來源名字(DSN),IP地址和Web路徑)都是很好的緩衝候選者。注意,不僅僅可以快取資料本身,還可以快取資料的表現。如果一個ASP頁面很少變化,並且緩衝代價比較高(比如,產品列表),可以考慮用靜態HTML頁面。

  技巧2:用Application對象或Session對象緩衝常用資料 

  ASP的Application和Session對象是一個極其方便的在記憶體中快取資料的容器。你可以把資料放到Application或Session對象中,這些資料就會在整個HTTP調用中一直存在。每個使用者有自己的Session對象中的資料,而Application對象中的資料可以在所有使用者中共用。 

  應該在什麼時候將資料裝入Application或Session中呢?通常,資料在Application或Session啟動的時候裝入。要想在Application或Session啟動的時候裝入資料,需要分別在Global.asa的Application_OnStart()或Session_OnStart()中添加適當的代碼;如果Global.asa中沒有這兩個函數,你可以手工添加。也可以在資料第一次使用的時候將其裝入。要想這樣,應該在ASP頁面中寫一些代碼(或是寫一個可重用的指令碼函數)來檢查資料是否存在並且如果資料不存在則將其裝入記憶體。下面是一個經典的效能調整技術--Lazy Evaluation: 

<% 
Function GetEmploymentStatusList 
 Dim d 
 d = Application("EmploymentStatusList") 
 If d = "" Then 
   ' FetchEmploymentStatusList function (not shown) 
   ' fetches data from DB, returns an Array 
   d = FetchEmploymentStatusList() 
   Application("EmploymentStatusList") = d 
 End If 
 GetEmploymentStatusList = d 
End Function 
%> 

Similar functions could be written for each chunk of data needed. 

In what format should the data be stored? Any variant type can be 
stored, since all script variables are variants. For instance, you 
can store strings, integers, or arrays. Often, you’ll be storing the 
contents of an ADO recordset in one of these variable types. To get 
data out of an ADO recordset, you can manually copy the data into 
VBScript variables, one field at a time. It’s faster and easier to 
use one of the ADO recordset persistence functions GetRows(),GetString 
() or Save() (ADO 2.5). Full details are beyond the scope of this 
article, but here’s a function that demonstrates using GetRows() to 
return an array of recordset data: 

' 擷取記錄集,返回數組 
Function FetchEmploymentStatusList 
 Dim rs 
 Set rs = CreateObject("ADODB.Recordset") 
 rs.Open "select StatusName, StatusID from EmployeeStatus", _ 
     "dsn=employees;uid=sa;pwd=;" 
 FetchEmploymentStatusList = rs.GetRows() ' 將記錄集用數組返回 
 rs.Close 
 Set rs = Nothing 
End Function 

A further refinement of the above might be to cache the HTML for the 
list, rather than the array. Here’s a simple sample: 

' 擷取記錄集,返回HTML Option列表 
Function FetchEmploymentStatusList 
 Dim rs, fldName, s 
 Set rs = CreateObject("ADODB.Recordset") 
 rs.Open "select StatusName, StatusID from EmployeeStatus", _ 
     "dsn=employees;uid=sa;pwd=;" 
 s = "<select name=""EmploymentStatus">" & vbCrLf 
 Set fldName = rs.Fields("StatusName") ' ADO 欄位綁定 
 Do Until rs.EOF 
  s = s & " <option>" & fldName & "</option>" & vbCrLf 
  rs.MoveNext 
 Loop 
 s = s & "</select>" & vbCrLf 
 rs.Close 
 Set rs = Nothing ' 釋放rs 
 FetchEmploymentStatusList = s ' 用字串方式返回資料 
End Function 

  在正確情況下,你可以將ADO記錄集本身緩衝在Application或Session範圍,但必須滿足下面兩個條件: .ADO必須被標記為自由執行緒模式(Free-threaded) .必須使用無串連記錄集 

  如果不能滿足上面兩個條件,一定不要緩衝記錄集。在下面的“不靈活的組件”和“不要緩衝Connection”兩個技巧中,我們將討論在Application和Session中儲存COM對象的危險性。 

  當你在Application或Session中儲存資料後,資料將一直儲存,知道你的程式改變它,或是Session到期,或是Web服務重新啟動。What if the data needs to be updated?手工重新整理Application資料,可以調用只有管理員才可訪問的用來重新整理資料的ASP頁面;或者週期性通過一個函數來周期性的更新資料。下面的例子在快取資料中儲存了一個時間戳記,然後一段時間之後自動重新整理資料。 

<% 
Const UPDATE_INTERVAL = 300 ' 重新整理間隔,單位是秒 

'返回僱員狀態列表 
Function GetEmploymentStatusList 
 UpdateEmploymentStatus 
 GetEmploymentStatusList = Application("EmploymentStatusList") 
End Function 

'周期性的更新緩衝中的資料 
Sub UpdateEmploymentStatusList 
 Dim d, strLastUpdate 
 strLastUpdate = Application("LastUpdate") 
 If (strLastUpdate = "") Or _ 
    (UPDATE_INTERVAL < DateDiff("s", strLastUpdate, Now)) Then 

   ' Note: two or more calls might get in here. This is okay and 
will simply 
   ' result in a few unnecessary fetches (there is a workaround 
for this) 

   ' FetchEmploymentStatusList function (not shown) 
   ' fetches data from DB, returns an Array 
   d = FetchEmploymentStatusList() 

   ' 更新Application對象時用Application.Lock()來保持資料一致性 
   Application.Lock 
   Application("EmploymentStatusList") = Events 
   Application("LastUpdate") = CStr(Now) 
   Application.Unlock 
 End If 
End Sub 

  要知道在Session或Application中緩衝大數組並不是一個太好的方法。在訪問數組中的任何元素之前,指令碼解譯器都需要產生一個臨時的整個數組的副本。例如,如果你緩衝了一個100,000個字串元素的數組,用來將郵遞區號和當地的天氣對應一一起來,在訪問數組中任何一個字串之前,ASP解譯器首先必須複製所有的100,000個天氣情況資料到一個臨時數組中。在這種情況下,開發一個組件來儲存天氣情況資料或是使用詞典(Dictioary)對象更為合適一點。不過,也不要因小失大,數組對象的的尋找速度更快。索引一個詞典比索引一個數組慢。你可以因你的情況而宜,選擇合適的資料結構。

  技巧3:在硬碟上快取資料和HTML頁面 

  有時,可能有太多的資料緩衝在記憶體中。“太多”是個模糊的說法,它取決與Web伺服器的記憶體大小、快取項目的數目和這些快取項目被訪問的頻度。無論如何,如果太多的資料在記憶體中緩衝,可以考慮將資料用文本或XML檔案快取到Web伺服器的硬碟上。可以將緩衝到硬碟上和到記憶體中結合起來,針對你的網站,找到最佳化的策略。 

  注意,當我們測量單一ASP頁面的效能時,從硬碟上讀取資料可能比從資料庫中讀取慢。但是,緩衝能夠減少資料庫和網路的負載。在高負載的情況下,這將大大提高總體輸送量。當被緩衝的資料是非常複雜的查詢,比如多表串連或是一個複雜的查詢過程或一個非常大的記錄集,緩衝的效果將非常明顯。 

  ASP和COM提供了一些工具來建立基於硬碟的緩衝方案。ADO Recordset對象的Save和Open方法可以儲存和裝入到磁碟上。還有一些用來訪問檔案的組件: .Scripting.FileSystemObject允許你建立、讀取和寫入檔案。 .MSXML,同IE捆綁的微軟的XML解譯器,支援儲存和裝入XML文檔。 .LookupTable對象是一個用來從磁碟裝入簡單列表的非常好的選擇。 

  最後,將資料表現緩衝在硬碟上,比快取資料本身要好。產生的HTML可以一個.htm或.asp檔案儲存在硬碟上;超連可以直接指向那些檔案。你也可以用一些商業工具,如XBuilder和SQL Server互連網發布特性,來產生和處理HTML檔案。另外,也可以用#include將HTML片段包含到ASP檔案中;還可以用FileSystemObject來讀取HTML檔案。

  技巧4:避免在Application或Session對象中緩衝COM對象 

  雖然在Application或Session對象中快取資料是一個好注意,但緩衝COM對象可能帶來嚴重的後果。在Application或Session對象中緩衝常用COM對象非常誘人,但非常不幸,很多COM對象,包括那些用VB 6.0或早期版本寫的組件,如果被緩衝到 
Application或Session對象中將會導致嚴重的效能瓶頸。 

  特別地,所有非Agile的組件被緩衝到Session或Application中時,都將產生效能瓶頸。Agile組件是指彙總了Free-threaded marshaler(FTM)並且執行緒模式是Both 
(ThreadingModel=Both),或執行緒模式是Neutral(Netural新出現在Windows 2000 
和COM+中)的組件。下面的組件都是非Agile的: 


  自由執行緒模式組件(除非他們彙總了FTM) 
  Apartment執行緒模式組件 
  單執行緒元件 

  Configured組件(MTS/COM+庫和服務包/應用)是非Agile的,除非它們是Neutral執行緒模式的。Apartment執行緒模式組件和其他非Agile組件最好是工作在頁面範圍內(就是說,他們在一個單一ASP頁面中建立和銷毀)。 

  在IIS 4.0中,執行緒模式是Both的組件被看作是Agile的,但在IIS 5.0中,他們不再滿足Agile的條件。組件執行緒模式必須是Both的,並且彙總了FTM,才被看作Agile的。如果試圖將一個用Server.CreateObject建立的非Agile組件儲存到 
Application對象中時,IIS 5.0將會拋出一個錯誤。 

  當ADO組件被標記為自由執行緒模式時,ADO記錄集對象可以安全地儲存。可以用Makfre15.bat,一般是放在\\program Files\Common\System\ADO這個檔案夾裡,將ADO組件標記為自由執行緒模式。有一點要注意:當用Access作後台資料庫時,ADO不能被標記為自由執行緒模式。詞典(Dictionary)組件也是Agile對象。

  技巧5:不要快取資料庫串連 

  緩衝ADO Connection對象是一個不好的策略。如果一個Connection對象被儲存在 
Application對象中並被所有頁面使用,所有頁面就會爭著使用這個串連。如果 
Connection對象被儲存在Session對象中,就要為每個使用者建立一個資料庫連接,這就消減了串連池的作用,並且增大了Web伺服器和資料庫伺服器的壓力。可以用在每個使用ADO的ASP頁建立和釋放ADO對象來替代快取資料庫串連;因為IIS內建了資料庫連接池,所以這種方法非常有效。 

  既然有串連的記錄集儲存了一個資料庫連接的引用,因此也不應該在Application或Session對象中儲存有串連的記錄集。但是,你可以安全的緩衝不需連線的記錄集,因為它並不包含到資料連線的引用。要想掛斷一個記錄集,可以採取如下兩個步驟: 

  Set rs = Server.CreateObject("ADODB.RecordSet") 
  rs.CursorLocation = adUseClient ' 第一步 

  rs.Open strQuery, strProv 

  ' 將記錄集同資料提供者和資料來源掛斷 
  rs.ActiveConnection = Nothing  '第二步 

  技巧6:正確地使用Session對象 

  我們已經提到了在Application和Session中快取資料的好處,下面我們將說一些 
Session對象的缺點。在繁忙的網站上使用Session有一些不利的地方。繁忙是指這個網站每秒鐘要處理數以百計的頁面請求或同時串連數以千計的並發使用者。這個技巧對那些必須要水平伸縮的網站--就是說,這些網站用多個伺服器來實現Server Load Balancer或容錯--非常重要。對小的網站,如公司內網,Session相對與他消耗的資源來說,還是值得一用的。 

  ASP自動為每個訪問Web伺服器的擁護建立一個Session對象。每個Session大約消耗10K的資源,並使所有的請求都慢了一點。這個Session在逾時周期內一直存在,這個周期一般是20分鐘。對於Session來說最大的問題不是效能而是伸縮能力。Session不是跨Web伺服器的;一旦一個Session在某個伺服器上建立,它的資料都儲存在那兒。 
  這意味著如果你要在多個Web伺服器環境中使用Session,你必須設計一套能使使用者總是訪問它的Session對象所在的Web伺服器的策略;即將一個使用者粘到一個Web伺服器上。如果Web伺服器崩潰,因為Session不是永久儲存在磁碟上的餓,所以全部“粘” 
  在其上的使用者的Session狀態都將丟失。實現“粘Session(sticky session)”的策略包括硬體和軟體方案,如Windows 2000 Advanced Server中的Network Load Balancing和Cisco的Local Director。當然,這些方案並不完美,都要損失一些延展性。Application對象也不是跨伺服器的,如果你想在多伺服器間共用和更新Application資料,你必須使用一個後台資料庫。但無論如何,唯讀Application資料在多伺服器環境中還是十分有用的。 

  絕大多數任務優先(mission-critical)的網站都想在至少兩台Web伺服器上發布--如果沒有比延長正常已耗用時間更重要的理由的話。因此,在設計階段,你就要實現“粘Session”,或是簡單地避免Session和其他將使用者狀態儲存在一個獨立Web伺服器上的狀態管理技術。 

  如果不使用Session,就將它們關閉;可以通過Internet Service Manager(參看ISM文檔)關閉你的應用的Session功能。如果決定使用Session,就要用一些方法將他們對效能的影響減到最小。可以將不需要Session的內容(如說明視窗等)移到一個的關閉了Session的ASP應用中。如果某個單一頁面不需要Session,可以將下面的語句放在頁面的頂部來禁止Session功能: 

<% @EnableSessionState=False %> 

  使用該語句還有一個原因是Session在幀中會產生一個有趣的問題。ASP保證任何時候一個會話只有一個請求,這就導致如果瀏覽器同時請求多個頁面,同一時刻將只有一個ASP請求能夠訪問Session;這避免了訪問Session對象時產生的多線程問題;但很不幸,一個幀中的多個頁面只能順序的產生,一個接著一個,而不是兵法。使用者可能會為多個幀等待較長時間。所以如果幀中的某個頁面沒有使用Session,就在頁面頂部放置<% @EnableSessionState=False %>語句。 

  作為使用Session對象的替代,還有很多其他的方法來管理工作階段狀態。對小規模的狀態(小於4KB),推薦使用Cookies,QueryString變數和隱藏表單變數。對大量資料,如購物資訊,一個後台資料庫可能是很好的選擇。

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

  如果有很多VBScript或JScript代碼,可以通過將代碼封裝到COM對象中來提高效能。 
編譯過的代碼通常比解釋代碼運行得快。COM對象可以通過“前期綁定”來訪問其他COM對象,這比指令碼使用的“後期綁定”更高效。 

  下面是將代碼碼封裝到COM對象中的優點(不僅僅是效能): 

  COM對象可以很好地將商業邏輯同表現邏輯分離 
  COM對象使代碼可重用 
  用VB,C或VJ寫的代碼比ASP代碼更易調試 

  COM對象也有不足,包括開發週期長和需要不同的編程經驗等。有一點尤需注意,封裝少量ASP代碼可能在效能上適得其反;這種情況下,建立和調用COM對象的代價超過了編譯代碼效能上的好處。如何組合ASP代碼和COM組件代碼來產生最佳效能,往往是個令人頭疼的問題。注意,同Windows NT 4.0/IIS 4.0相比,Windows 2000/IIS 5.0在指令碼和ADO效能上已經大大提高。

  技巧8:對資源晚擷取,早釋放 

  通常情況下,晚擷取和早釋放資源是最好的。這不僅適用於COM對象,也適用於檔案控制代碼和其他資源。ADO串連和記錄集是這項最佳化策略的主要對象。當使用完一個Recordset對象,應該立即將它釋放,而不應等到頁面結束。將VBScript變數設成Nothing是最好的方法。同時,釋放相關的Command和Connection對象(別忘了在將Connection對象設成Nothing之前調用Close()方法)。 

  技巧9:進程外執行以效能換取可靠性 

  ASP和MTS/COM+都有選項讓你來用可靠性換取效能。當建立和發布你的應用時,你應該理解這項交易的內幕。 

  ASP選項 

  ASP應用有三種運行方法可選擇。在IIS 5.0中,引入“分離層級(isolation level)”這個術語來描述這些選項。三種分離層級分別是:低(Low),中 (Medium)和高(High)。 

  低分離級 這種層級被所有版本的IIS支援,並且速度也是最快的。它在Inetinfo.exe--主要的IIS進程--中運行ASP。如果ASP應用崩潰,IIS也將崩潰。

  (在IIS 4.0中,網管必須用諸如InetMon之類的工具來監視IIS,一旦IIS停止,運行批次檔。IIS 5.0引入了“可靠的重啟(reliable restart)”,會自動重新啟動失敗的伺服器。

  中分離級 從IIS 5.0開始引入的新層級,指進程外運行,即ASP運行在IIS進程之外。 在中分離級中,所有的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進程外應用比II4 4.0中的進程內運行都快。但無論如何,在任何平台上,還是進程內(低分離級)運行能帶來最佳的效能。然而,在相對低點擊率或低最大輸送量的情況下,低分離級不會帶來任何益處;因此,除非每個Web伺服器需要應付成千上百的頁面請求,不然你不會需要用低分離級。通常,需要在多個配置下進行測試,才能決定使用哪種配置。

  注意:當在進程外運行ASP應用時(中或低分離級),ASP應用運行在NT 4上的MTS中或Windows 2000的COM+中;就是說,在NT4中,ASP應用運行在Mtx.exe中;在 
Windows 2000中,ASP應用運行在DllHost.exe中。你可以在工作管理員中看到這些進程在運行。 

  COM選項 

  COM組件也有三種配置選項,但不完全對應於ASP的選項。COM組件可以是“無配置的(Unconfigured)”、作為一個庫應用(Library Application)或是作為一個服務應用(Server Application)。“無配置的”意味著組件不註冊到COM+中,組件將在調用者進程空間中運行;即“進程內”。庫應用也是進程內的,但可以從COM+的服務,如安全、事務和上下文支援,中獲益。服務應用則被配置成運行在自己的進程空間內。 

“無配置”比庫應用有一點優越性;而庫應用比服務應用在效能上更優越。這是因為庫應用和ASP是在同一個進程內的,而服務應用是運行在自己的進程空間裡的。進程間調用比進程內調用的代價高。同樣,在進程間傳遞如記錄集這樣的資料,需要在兩個進程間複製所有的資料。 

  缺陷!當使用COM服務應用時,要想在ASP和COM間傳送資料,必須保證對象實現了“按值排列(marshall-by-valu)”,或者說MBV。實現了MBV的對象將自身從一個進程複製到另一個進程。這比下面的方法好:對象留在建立者進程,其他進程重複調用建立進程來使用對象。無串連ADO記錄集是MBV,有串連記錄集就不是。 

  Scripting.Dictonary對象沒有實現MBV,不能在進程之間傳遞。最後,對VB程式員的一個提示:MBV不是通過用ByVal來傳遞參數。MBV是原始組件作者實現的。 

  怎樣做? 
  推薦的用可靠性換取效能的配置: 

  在IIS 4.0上,用ASP的低分離級,並使用MTS服務包。 
  在IIS 5.0SHANG,用ASP的中分離級,使用COM+的庫應用。 

  技巧10:使用Option Explicit

  在.asp檔案中使用Option Explicit。該指示放在.asp檔案的頂部,強制開發人員在使用任何變數之前必須定義它。許多程式員認為這有助於偵錯工具,因為它消除了打字錯誤的可能(如將MyXMLString=敲成MyXLMString=) 

  另外一點可能更加重要:已定義變數比未定義的變數快。ASP每次是用名字來引用未定義變數的;而另一方面,每個已定義變數有一個序號,ASP用這個序號來引用已定義變數。既然Option Explicit強制變數定義,就保證了所有的變數都是已定義的,訪問速度就更快了。

  技巧11:在子過程和函數中使用本地變數

  本地變數是那些在子過程和函數中定義的變數。在函數和子過程中,訪問本地變數比訪問全域變數更快。使用本地變數也使代碼更乾淨,因此盡量使用本地變數吧。



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。