22個(gè)提高ASP性能的技巧(1-12)
作者:未知


介紹
對(duì)于ASP程序來說,性能非常重要;必須在最初設(shè)計(jì)程序時(shí)就要考慮到性能,否則以后恐怕就要因?yàn)樾阅軉栴}而重寫代碼。怎樣才能使ASP程序性能達(dá)到最大呢?本文就將介紹一些提高ASP程序性能的技巧。

技巧1:將常用數(shù)據(jù)在Web服務(wù)器端緩存起來
大部分的ASP頁(yè)面都要從后臺(tái)數(shù)據(jù)庫(kù)中提取數(shù)據(jù),然后將數(shù)據(jù)用HTML方式表現(xiàn)出來。
不管你的數(shù)據(jù)庫(kù)多么快,從內(nèi)存中提取數(shù)據(jù)總比從后臺(tái)數(shù)據(jù)庫(kù)中提取快;從本地硬盤中讀取數(shù)據(jù)通常也比從數(shù)據(jù)庫(kù)中快。因此,你可以通過在Web服務(wù)器端緩存數(shù)據(jù)來提高性能。

緩存是個(gè)典型的以空間換取時(shí)間的交易。如果你正確的緩存了數(shù)據(jù),性能可能會(huì)突飛猛進(jìn)。要想一個(gè)緩存能真正發(fā)揮效益,必須緩沖那些常用和計(jì)算復(fù)雜的數(shù)據(jù)。裝滿過期數(shù)據(jù)的緩沖區(qū)只能浪費(fèi)內(nèi)存。

不經(jīng)常變化的數(shù)據(jù)也是緩存的一個(gè)良好候選者,因?yàn)槟憧梢圆挥藐P(guān)心同數(shù)據(jù)庫(kù)中的數(shù)據(jù)保持同步。下拉列表框、引用表、小段DHTML代碼,XML字符串、菜單項(xiàng)和站點(diǎn)配置變量(包括數(shù)據(jù)源名字(DSN),IP地址和Web路徑)都是很好的緩存候選者。注意,不僅僅可以緩存數(shù)據(jù)本身,還可以緩存數(shù)據(jù)的表現(xiàn)。如果一個(gè)ASP頁(yè)面很少變化,并且緩存代價(jià)比較高(比如,產(chǎn)品列表),可以考慮用靜態(tài)HTML頁(yè)面。

技巧2:用Application對(duì)象或Session對(duì)象緩存常用數(shù)據(jù)
ASP的Application和Session對(duì)象是一個(gè)極其方便的在內(nèi)存中緩存數(shù)據(jù)的容器。你可以把數(shù)據(jù)放到Application或Session對(duì)象中,這些數(shù)據(jù)就會(huì)在整個(gè)HTTP調(diào)用中一直存在。每個(gè)用戶有自己的Session對(duì)象中的數(shù)據(jù),而Application對(duì)象中的數(shù)據(jù)可以在所有用戶中共享。

應(yīng)該在什么時(shí)候?qū)?shù)據(jù)裝入Application或Session中呢?通常,數(shù)據(jù)在Application或Session啟動(dòng)的時(shí)候裝入。要想在Application或Session啟動(dòng)的時(shí)候裝入數(shù)據(jù),需要分別在Global.asa的Application_OnStart()或Session_OnStart()中添加適當(dāng)?shù)拇a;如果Global.asa中沒有這兩個(gè)函數(shù),你可以手工添加。也可以在數(shù)據(jù)第一次使用的時(shí)候?qū)⑵溲b入。要想這樣,應(yīng)該在ASP頁(yè)面中寫一些代碼(或是寫一個(gè)可重用的腳本函數(shù))來檢查數(shù)據(jù)是否存在并且如果數(shù)據(jù)不存在則將其裝入內(nèi)存。下面是一個(gè)經(jīng)典的性能調(diào)整技術(shù)--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:

' 獲取記錄集,返回?cái)?shù)組
Function FetchEmploymentStatusList
 Dim rs
 Set rs = CreateObject("ADODB.Recordset")
 rs.Open "select StatusName, StatusID from EmployeeStatus", _
     "dsn=employees;uid=sa;pwd=;"
 FetchEmploymentStatusList = rs.GetRows() ' 將記錄集用數(shù)組返回
 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 ' 用字符串方式返回?cái)?shù)據(jù)
End Function

在正確情況下,你可以將ADO記錄集本身緩存在Application或Session范圍,但必須滿足下面兩個(gè)條件: .ADO必須被標(biāo)記為自由線程模型(Free-threaded) .必須使用無(wú)連接記錄集

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

當(dāng)你在Application或Session中存儲(chǔ)數(shù)據(jù)后,數(shù)據(jù)將一直保存,知道你的程序改變它,或是Session過期,或是Web服務(wù)重新啟動(dòng)。What if the data needs to be updated?手工刷新Application數(shù)據(jù),可以調(diào)用只有管理員才可訪問的用來刷新數(shù)據(jù)的ASP頁(yè)面;或者定期的通過一個(gè)函數(shù)來周期性的更新數(shù)據(jù)。下面的例子在緩存數(shù)據(jù)中保存了一個(gè)時(shí)間戳,然后一段時(shí)間之后自動(dòng)刷新數(shù)據(jù)。

<%
Const UPDATE_INTERVAL = 300 ' 刷新間隔,單位是秒

'返回雇員狀態(tài)列表
Function GetEmploymentStatusList
 UpdateEmploymentStatus
 GetEmploymentStatusList = Application("EmploymentStatusList")
End Function

'周期性的更新緩存中的數(shù)據(jù)
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對(duì)象時(shí)用Application.Lock()來保持?jǐn)?shù)據(jù)一致性
   Application.Lock
   Application("EmploymentStatusList") = Events
   Application("LastUpdate") = CStr(Now)
   Application.Unlock
 End If
End Sub

要知道在Session或Application中緩存大數(shù)組并不是一個(gè)太好的方法。在訪問數(shù)組中的任何元素之前,腳本解釋器都需要生成一個(gè)臨時(shí)的整個(gè)數(shù)組的副本。例如,如果你緩存了一個(gè)100,000個(gè)字符串元素的數(shù)組,用來將郵政編碼和當(dāng)?shù)氐奶鞖鈱?duì)應(yīng)一一起來,在訪問數(shù)組中任何一個(gè)字符串之前,ASP解釋器首先必須復(fù)制所有的100,000個(gè)天氣情況數(shù)據(jù)到一個(gè)臨時(shí)數(shù)組中。在這種情況下,開發(fā)一個(gè)組件來儲(chǔ)存天氣情況數(shù)據(jù)或是使用詞典(Dictioary)對(duì)象更為合適一點(diǎn)。不過,也不要因小失大,數(shù)組對(duì)象的的查找速度更快。索引一個(gè)詞典比索引一個(gè)數(shù)組慢。你可以因你的情況而宜,選擇合適的數(shù)據(jù)結(jié)構(gòu)。

技巧3:在硬盤上緩存數(shù)據(jù)和HTML頁(yè)面
有時(shí),可能有太多的數(shù)據(jù)緩存在內(nèi)存中?!疤唷笔莻€(gè)模糊的說法,它取決與Web服務(wù)器的內(nèi)存大小、緩存項(xiàng)的數(shù)目和這些緩存項(xiàng)被訪問的頻度。無(wú)論如何,如果太多的數(shù)據(jù)在內(nèi)存中緩存,可以考慮將數(shù)據(jù)用文本或XML文件緩存到Web服務(wù)器的硬盤上??梢詫⒕彺娴接脖P上和到內(nèi)存中結(jié)合起來,針對(duì)你的站點(diǎn),找到最優(yōu)化的策略。

注意,當(dāng)我們測(cè)量單一ASP頁(yè)面的性能時(shí),從硬盤上讀取數(shù)據(jù)可能比從數(shù)據(jù)庫(kù)中讀取慢。但是,緩存能夠減少數(shù)據(jù)庫(kù)和網(wǎng)絡(luò)的負(fù)載。在高負(fù)載的情況下,這將大大提高總體吞吐量。當(dāng)被緩存的數(shù)據(jù)是非常復(fù)雜的查詢,比如多表連接或是一個(gè)復(fù)雜的查詢過程或一個(gè)非常大的記錄集,緩存的效果將非常明顯。

ASP和COM提供了一些工具來建立基于硬盤的緩存方案。ADO Recordset對(duì)象的Save和Open方法可以保存和裝入到磁盤上。還有一些用來訪問文件的組件: .Scripting.FileSystemObject允許你創(chuàng)建、讀取和寫入文件。 .MSXML,同IE捆綁的微軟的XML解釋器,支持保存和裝入XML文檔。 .LookupTable對(duì)象是一個(gè)用來從磁盤裝入簡(jiǎn)單列表的非常好的選擇。

最后,將數(shù)據(jù)表現(xiàn)緩存在硬盤上,比緩存數(shù)據(jù)本身要好。生成的HTML可以一個(gè).htm或.asp文件保存在硬盤上;超連可以直接指向那些文件。你也可以用一些商業(yè)工具,如XBuilder和SQL Server互連網(wǎng)發(fā)布特性,來生成和處理HTML文件。另外,也可以用#include將HTML片段包含到ASP文件中;還可以用FileSystemObject來讀取HTML文件。

技巧4:避免在Application或Session對(duì)象中緩存COM對(duì)象
雖然在Application或Session對(duì)象中緩存數(shù)據(jù)是一個(gè)好注意,但緩存COM對(duì)象可能帶來嚴(yán)重的后果。在Application或Session對(duì)象中緩存常用COM對(duì)象非常誘人,但非常不幸,很多COM對(duì)象,包括那些用VB 6.0或早期版本寫的組件,如果被緩存到Application或Session對(duì)象中將會(huì)導(dǎo)致嚴(yán)重的性能瓶頸。

特別地,所有非Agile的組件被緩存到Session或Application中時(shí),都將產(chǎn)生性能瓶頸。Agile組件是指聚合了Free-threaded marshaler(FTM)并且線程模型是Both
(ThreadingModel=Both),或線程模型是Neutral(Netural新出現(xiàn)在Windows 2000
和COM+中)的組件。下面的組件都是非Agile的:


自由線程模型組件(除非他們聚合了FTM)
Apartment線程模型組件
單線程組件

Configured組件(MTS/COM+庫(kù)和服務(wù)包/應(yīng)用)是非Agile的,除非它們是Neutral線程模型的。Apartment線程模型組件和其他非Agile組件最好是工作在頁(yè)面范圍內(nèi)(就是說,他們?cè)谝粋€(gè)單一ASP頁(yè)面中創(chuàng)建和銷毀)。

在IIS 4.0中,線程模型是Both的組件被看作是Agile的,但在IIS 5.0中,他們不再滿足Agile的條件。組件線程模型必須是Both的,并且聚合了FTM,才被看作Agile的。如果試圖將一個(gè)用Server.CreateObject創(chuàng)建的非Agile組件存儲(chǔ)到Application對(duì)象中時(shí),IIS 5.0將會(huì)拋出一個(gè)錯(cuò)誤。

當(dāng)ADO組件被標(biāo)記為自由線程模型時(shí),ADO記錄集對(duì)象可以安全地存儲(chǔ)。可以用Makfre15.bat,一般是放在\\Program Files\Common\System\ADO這個(gè)文件夾里,將ADO組件標(biāo)記為自由線程模型。有一點(diǎn)要注意:當(dāng)用Access作后臺(tái)數(shù)據(jù)庫(kù)時(shí),ADO不能被標(biāo)記為自由線程模型。詞典(Dictionary)組件也是Agile對(duì)象。

技巧5:不要緩存數(shù)據(jù)庫(kù)連接
緩存ADO Connection對(duì)象是一個(gè)不好的策略。如果一個(gè)Connection對(duì)象被存儲(chǔ)在Application對(duì)象中并被所有頁(yè)面使用,所有頁(yè)面就會(huì)爭(zhēng)著使用這個(gè)連接。如果Connection對(duì)象被存儲(chǔ)在Session對(duì)象中,就要為每個(gè)用戶創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接,這就消減了連接池的作用,并且增大了Web服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器的壓力??梢杂迷诿總€(gè)使用ADO的ASP頁(yè)創(chuàng)建和釋放ADO對(duì)象來替代緩存數(shù)據(jù)庫(kù)連接;因?yàn)镮IS內(nèi)建了數(shù)據(jù)庫(kù)連接池,所以這種方法非常有效。

既然有連接的記錄集保存了一個(gè)數(shù)據(jù)庫(kù)連接的引用,因此也不應(yīng)該在Application或Session對(duì)象中保存有連接的記錄集。但是,你可以安全的緩存無(wú)連接的記錄集,因?yàn)樗⒉话綌?shù)據(jù)連接的引用。要想掛斷一個(gè)記錄集,可以采取如下兩個(gè)步驟:

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

  rs.Open strQuery, strProv

  ' 將記錄集同數(shù)據(jù)提供者和數(shù)據(jù)源掛斷
  rs.ActiveConnection = Nothing  '第二步

技巧6:正確地使用Session對(duì)象
我們已經(jīng)提到了在Application和Session中緩存數(shù)據(jù)的好處,下面我們將說一些Session對(duì)象的缺點(diǎn)。在繁忙的站點(diǎn)上使用Session有一些不利的地方。繁忙是指這個(gè)站點(diǎn)每秒鐘要處理數(shù)以百計(jì)的頁(yè)面請(qǐng)求或同時(shí)連接數(shù)以千計(jì)的并發(fā)用戶。這個(gè)技巧對(duì)那些必須要水平伸縮的站點(diǎn)--就是說,這些站點(diǎn)用多個(gè)服務(wù)器來實(shí)現(xiàn)負(fù)載平衡或容錯(cuò)--非常重要。對(duì)小的站點(diǎn),如公司內(nèi)網(wǎng),Session相對(duì)與他消耗的資源來說,還是值得一用的。

ASP自動(dòng)為每個(gè)訪問Web服務(wù)器的擁護(hù)創(chuàng)建一個(gè)Session對(duì)象。每個(gè)Session大約消耗10K的資源,并使所有的請(qǐng)求都慢了一點(diǎn)。這個(gè)Session在超時(shí)周期內(nèi)一直存在,這個(gè)周期一般是20分鐘。對(duì)于Session來說最大的問題不是性能而是伸縮能力。Session不是跨Web服務(wù)器的;一旦一個(gè)Session在某個(gè)服務(wù)器上創(chuàng)建,它的數(shù)據(jù)都保存在那兒。
這意味著如果你要在多個(gè)Web服務(wù)器環(huán)境中使用Session,你必須設(shè)計(jì)一套能使用戶總是訪問它的Session對(duì)象所在的Web服務(wù)器的策略;即將一個(gè)用戶粘到一個(gè)Web服務(wù)器上。如果Web服務(wù)器崩潰,因?yàn)镾ession不是永久保存在磁盤上的餓,所以全部“粘”
在其上的用戶的Session狀態(tài)都將丟失。實(shí)現(xiàn)“粘Session(sticky session)”的策略包括硬件和軟件方案,如Windows 2000 Advanced Server中的Network Load Balancing和Cisco的Local Director。當(dāng)然,這些方案并不完美,都要損失一些可伸縮性。Application對(duì)象也不是跨服務(wù)器的,如果你想在多服務(wù)器間共享和更新Application數(shù)據(jù),你必須使用一個(gè)后臺(tái)數(shù)據(jù)庫(kù)。但無(wú)論如何,只讀Application數(shù)據(jù)在多服務(wù)器環(huán)境中還是十分有用的。

絕大多數(shù)任務(wù)優(yōu)先(mission-critical)的站點(diǎn)都想在至少兩臺(tái)Web服務(wù)器上發(fā)布--如果沒有比延長(zhǎng)正常運(yùn)行時(shí)間更重要的理由的話。因此,在設(shè)計(jì)階段,你就要實(shí)現(xiàn)“粘Session”,或是簡(jiǎn)單地避免Session和其他將用戶狀態(tài)保存在一個(gè)獨(dú)立Web服務(wù)器上的狀態(tài)管理技術(shù)。

如果不使用Session,就將它們關(guān)閉;可以通過Internet Service Manager(參看ISM文檔)關(guān)閉你的應(yīng)用的Session功能。如果決定使用Session,就要用一些方法將他們對(duì)性能的影響減到最小??梢詫⒉恍枰猄ession的內(nèi)容(如幫助窗口等)移到一個(gè)的關(guān)閉了Session的ASP應(yīng)用中。如果某個(gè)單一頁(yè)面不需要Session,可以將下面的語(yǔ)句放在頁(yè)面的頂部來禁止Session功能:

<% @EnableSessionState=False %>

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


作為使用Session對(duì)象的替代,還有很多其他的方法來管理會(huì)話狀態(tài)。對(duì)小規(guī)模的狀態(tài)(小于4KB),推薦使用Cookies,QueryString變量和隱藏表單變量。對(duì)大量數(shù)據(jù),如購(gòu)物信息,一個(gè)后臺(tái)數(shù)據(jù)庫(kù)可能是很好的選擇。

技巧7:將代碼封裝到COM對(duì)象中
如果有很多VBScript或JScript代碼,可以通過將代碼封裝到COM對(duì)象中來提高性能。編譯過的代碼通常比解釋代碼運(yùn)行得快。COM對(duì)象可以通過“前期綁定”來訪問其他COM對(duì)象,這比腳本使用的“后期綁定”更高效。

下面是將代碼碼封裝到COM對(duì)象中的優(yōu)點(diǎn)(不僅僅是性能):


COM對(duì)象可以很好地將商業(yè)邏輯同表現(xiàn)邏輯分離
COM對(duì)象使代碼可重用
用VB,C或VJ寫的代碼比ASP代碼更易調(diào)試

COM對(duì)象也有不足,包括開發(fā)周期長(zhǎng)和需要不同的編程經(jīng)驗(yàn)等。有一點(diǎn)尤需注意,封裝少量ASP代碼可能在性能上適得其反;這種情況下,創(chuàng)建和調(diào)用COM對(duì)象的代價(jià)超過了編譯代碼性能上的好處。如何組合ASP代碼和COM組件代碼來產(chǎn)生最佳性能,往往是個(gè)令人頭疼的問題。注意,同Windows NT 4.0/IIS 4.0相比,Windows 2000/IIS 5.0在腳本和ADO性能上已經(jīng)大大提高。

技巧8:對(duì)資源晚獲取,早釋放
通常情況下,晚獲取和早釋放資源是最好的。這不僅適用于COM對(duì)象,也適用于文件句柄和其他資源。ADO連接和記錄集是這項(xiàng)優(yōu)化策略的主要對(duì)象。當(dāng)使用完一個(gè)Recordset對(duì)象,應(yīng)該立即將它釋放,而不應(yīng)等到頁(yè)面結(jié)束。將VBScript變量設(shè)成Nothing是最好的方法。同時(shí),釋放相關(guān)的Command和Connection對(duì)象(別忘了在將Connection對(duì)象設(shè)成Nothing之前調(diào)用Close()方法)。

技巧9:進(jìn)程外執(zhí)行以性能換取可靠性
ASP和MTS/COM+都有選項(xiàng)讓你來用可靠性換取性能。當(dāng)建立和發(fā)布你的應(yīng)用時(shí),你應(yīng)該理解這項(xiàng)交易的內(nèi)幕。

ASP選項(xiàng)
ASP應(yīng)用有三種運(yùn)行方法可選擇。在IIS 5.0中,引入“分離級(jí)別(isolation
level)”這個(gè)術(shù)語(yǔ)來描述這些選項(xiàng)。三種分離級(jí)別分別是:低(Low),中
(Medium)和高(High)。

低分離級(jí) 這種級(jí)別被所有版本的IIS支持,并且速度也是最快的。它在
Inetinfo.exe--主要的IIS進(jìn)程--中運(yùn)行ASP。如果ASP應(yīng)用崩潰,IIS也將崩潰。
(在IIS 4.0中,網(wǎng)管必須用諸如InetMon之類的工具來監(jiān)視IIS,一旦IIS停止,運(yùn)行批處理文件。IIS 5.0引入了“可靠的重啟(reliable restart)”,會(huì)自動(dòng)重新啟動(dòng)失敗的服務(wù)器。
中分離級(jí) 從IIS 5.0開始引入的新級(jí)別,指進(jìn)程外運(yùn)行,即ASP運(yùn)行在IIS進(jìn)程之外。
在中分離級(jí)中,所有的ASP應(yīng)用共享一個(gè)進(jìn)程空間。把多個(gè)進(jìn)程外應(yīng)用在同個(gè)空間中運(yùn)行,減少了進(jìn)程的樹木。中分離級(jí)是IIS 5.0的默認(rèn)級(jí)別。
高分離級(jí) IIS 4.0和IIS 5.0都支持。高分離級(jí)也是進(jìn)程外的。如果ASP崩潰了,Web服務(wù)器并不崩潰。ASP應(yīng)用會(huì)在下個(gè)ASP請(qǐng)求到達(dá)的時(shí)候自動(dòng)重啟。每個(gè)被配置為高分離級(jí)的ASP應(yīng)用有自己的進(jìn)程空間;這將每個(gè)ASP應(yīng)用保護(hù)起來。它的缺點(diǎn)是對(duì)每個(gè)ASP應(yīng)用需要一個(gè)分離的進(jìn)程;這增加了許多資源消耗。
哪種選項(xiàng)是最好的。在IIS 4.0中,進(jìn)程外運(yùn)行將使性能急劇下降;在IIS 5.0中,許多改進(jìn)使進(jìn)程外ASP應(yīng)用的代價(jià)降到最低。事實(shí)上,在許多測(cè)試中,IIS 5.0中的ASP進(jìn)程外應(yīng)用比II4 4.0中的進(jìn)程內(nèi)運(yùn)行都快。但無(wú)論如何,在任何平臺(tái)上,還是進(jìn)程內(nèi)(低分離級(jí))運(yùn)行能帶來最佳的性能。然而,在相對(duì)低點(diǎn)擊率或低最大吞吐量的情況下,低分離級(jí)不會(huì)帶來任何益處;因此,除非每個(gè)Web服務(wù)器需要應(yīng)付成千上百的頁(yè)面請(qǐng)求,不然你不會(huì)需要用低分離級(jí)。通常,需要在多個(gè)配置下進(jìn)行測(cè)試,才能決定使用哪種配置。
注意:當(dāng)在進(jìn)程外運(yùn)行ASP應(yīng)用時(shí)(中或低分離級(jí)),ASP應(yīng)用運(yùn)行在NT 4上的MTS中或Windows 2000的COM+中;就是說,在NT4中,ASP應(yīng)用運(yùn)行在Mtx.exe中;在Windows 2000中,ASP應(yīng)用運(yùn)行在DllHost.exe中。你可以在任務(wù)管理器中看到這些進(jìn)程在運(yùn)行。

COM選項(xiàng)
COM組件也有三種配置選項(xiàng),但不完全對(duì)應(yīng)于ASP的選項(xiàng)。COM組件可以是“無(wú)配置的(Unconfigured)”、作為一個(gè)庫(kù)應(yīng)用(Library Application)或是作為一個(gè)服務(wù)應(yīng)用(Server Application)?!盁o(wú)配置的”意味著組件不注冊(cè)到COM+中,組件將在調(diào)用者進(jìn)程空間中運(yùn)行;即“進(jìn)程內(nèi)”。庫(kù)應(yīng)用也是進(jìn)程內(nèi)的,但可以從COM+的服務(wù),如安全、事務(wù)和上下文支持,中獲益。服務(wù)應(yīng)用則被配置成運(yùn)行在自己的進(jìn)程空間內(nèi)。

“無(wú)配置”比庫(kù)應(yīng)用有一點(diǎn)優(yōu)越性;而庫(kù)應(yīng)用比服務(wù)應(yīng)用在性能上更優(yōu)越。這是因?yàn)閹?kù)應(yīng)用和ASP是在同一個(gè)進(jìn)程內(nèi)的,而服務(wù)應(yīng)用是運(yùn)行在自己的進(jìn)程空間里的。進(jìn)程間調(diào)用比進(jìn)程內(nèi)調(diào)用的代價(jià)高。同樣,在進(jìn)程間傳遞如記錄集這樣的數(shù)據(jù),需要在兩個(gè)進(jìn)程間復(fù)制所有的數(shù)據(jù)。

缺陷!當(dāng)使用COM服務(wù)應(yīng)用時(shí),要想在ASP和COM間傳送數(shù)據(jù),必須保證對(duì)象實(shí)現(xiàn)了“按值排列(marshall-by-valu)”,或者說MBV。實(shí)現(xiàn)了MBV的對(duì)象將自身從一個(gè)進(jìn)程復(fù)制到另一個(gè)進(jìn)程。這比下面的方法好:對(duì)象留在創(chuàng)建者進(jìn)程,其他進(jìn)程重復(fù)調(diào)用創(chuàng)建進(jìn)程來使用對(duì)象。無(wú)連接ADO記錄集是MBV,有連接記錄集就不是。
Scripting.Dictonary對(duì)象沒有實(shí)現(xiàn)MBV,不能在進(jìn)程之間傳遞。最后,對(duì)VB程序員的一個(gè)提示:MBV不是通過用ByVal來傳遞參數(shù)。MBV是原始組件作者實(shí)現(xiàn)的。

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

在IIS 4.0上,用ASP的低分離級(jí),并使用MTS服務(wù)包。
在IIS 5.0SHANG,用ASP的中分離級(jí),使用COM+的庫(kù)應(yīng)用。
技巧10:使用Option Explicit
在.asp文件中使用Option Explicit。該指示放在.asp文件的頂部,強(qiáng)制開發(fā)者在使用任何變量之前必須定義它。許多程序員認(rèn)為這有助于調(diào)試程序,因?yàn)樗舜蜃皱e(cuò)誤的可能(如將MyXMLString=敲成MyXLMString=)

另外一點(diǎn)可能更加重要:已定義變量比未定義的變量快。ASP每次是用名字來引用未定義變量的;而另一方面,每個(gè)已定義變量有一個(gè)序號(hào),ASP用這個(gè)序號(hào)來引用已定義變量。既然Option Explicit強(qiáng)制變量定義,就保證了所有的變量都是已定義的,訪問速度就更快了。

技巧11:在子過程和函數(shù)中使用本地變量
本地變量是那些在子過程和函數(shù)中定義的變量。在函數(shù)和子過程中,訪問本地變量比訪問全局變量更快。使用本地變量也使代碼更干凈,因此盡量使用本地變量吧。

技巧12:將常用數(shù)據(jù)復(fù)制到腳本變量中
當(dāng)訪問ASP中的COM對(duì)象時(shí),應(yīng)該將常用對(duì)象數(shù)據(jù)復(fù)制到腳本變量中。著將減少COM方法調(diào)用。而COM方法調(diào)用代價(jià)相對(duì)比訪問腳本數(shù)據(jù)更高。當(dāng)訪問Collection和Dictonary對(duì)象時(shí),這項(xiàng)技術(shù)也能消減高昂的查詢代價(jià)。

通常,當(dāng)準(zhǔn)備不止一次訪問一個(gè)對(duì)象數(shù)據(jù)時(shí),應(yīng)該將這個(gè)數(shù)據(jù)放當(dāng)一個(gè)腳本對(duì)象中。
這項(xiàng)優(yōu)化的主要目標(biāo)是Request變量(Form和QueryString變量)。例如,你的站點(diǎn)傳遞一個(gè)叫UserID的QueryString變量,假定在一個(gè)特定頁(yè)UserID被引用十次。在ASP頁(yè)面的頂部,將UserID的值賦給一個(gè)變量,來替代十次的調(diào)用Request("UserID"),將接生9次COM調(diào)用。

在實(shí)際中,訪問COM屬性或方法的昂貴代價(jià)可能比較隱蔽。下面是一個(gè)例子,顯示一段普通的代碼:

Foo.bar.blah.baz = Foo.bar.blah.qaz(1)
If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ' ...

下面是這段代碼運(yùn)行的步驟:

1. 變量Foo被解析為一個(gè)全局對(duì)象
2. 變量bar被解析為Foo的一個(gè)成員。這觸發(fā)一次COM方法調(diào)用
3. 變量blash被解析為Foo.bar的一個(gè)成員。同樣,這也觸發(fā)一次COM方法調(diào)用
4. 變量qaz被解析為Foo.bar.blash的一個(gè)成員。對(duì),這也觸發(fā)一次COM方法調(diào)用
5. 調(diào)用 Foo.bar.blah.qaz(1)。一個(gè)或多個(gè)COM方法調(diào)用。獲取圖片?
6. 重復(fù)步驟1到步驟3來解析baz。系統(tǒng)不知道調(diào)用qaz是否會(huì)改變對(duì)象模型,所以步驟1到步驟3又執(zhí)行了一次,來解析baz
7. 解析出baz是Foo.bar.blah的一個(gè)成員,執(zhí)行屬性put.
8. 重復(fù)步驟1到步驟3來解析zaq
9. 重復(fù)步驟1到步驟3來解析abc

正如你所看到的,這是多么低效(并且慢)??焖俚姆椒ㄊ前慈缦麓a寫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語(yǔ)句:

With Foo.bar.blah
  .baz = .qaz(1)
  If .zaq = .abc Then '...
  ...
End With
標(biāo)簽:

相關(guān)文章

隨機(jī)推薦