簡介 編寫 ASP 頁面時
開發人員實際上是創建一個格式化的文本流
通過 ASP 提供的 Response 對象寫入 Web 客戶端
創建此文本流的方法有多種
而您選擇的方法將對 Web 應用程序的性能和可縮放性產生很大影響
很多次
在我幫助客戶優化其 Web 應用程序的性能時
發現其中一個比較有效的方法是更改 HTML 流的創建方式
本文將介紹幾種常用技術
並測試它們對一個簡單的 ASP 頁面的性能所產生的影響
ASP 設計 許多 ASP 開發人員都遵循良好的軟件工程原則
盡可能地將其代碼模塊化
這種設計通常使用一些包含文件
這些文件中包含對頁面的特定不連續部分進行格式化生成的函數
這些函數的字符串輸出(通常是 HTML 表格代碼)可以通過各種組合創建一個完整的頁面
某些開發人員對此方法進行了改進
將這些 HTML 函數移到 Visual Basic COM 組件中
希望充分利用已編譯的代碼提供的額外性能
盡管這種設計方法很不錯
但創建組成這些不連續 HTML 代碼組件的字符串所使用的方法將對 Web 站點的性能和可縮放性產生很大的影響
無論實際的操作是在 ASP 包含文件中執行還是在 Visual Basic COM 組件中執行
字符串連接 請看以下 WriteHTML 函數的代碼片斷
名為 Data 的參數只是一個字符串數組
其中包含一些要格式化為表格結構的數據(例如
從數據庫返回的數據)
Function WriteHTML( Data )
Dim nRep
For nRep =
to
sHTML = sHTML & vbcrlf _
&
<TR><TD>
& (nRep +
) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD></TR>
Next
WriteHTML = sHTML
End Function
這是很多 ASP 和 Visual Basic 開發人員創建 HTML 代碼時常用的方法
sHTML 變量中包含的文本返回到調用代碼
然後使用 Response
Write 寫入客戶端
當然
這還可以表示為直接嵌入不包含 WriteHTML 函數的頁面的類似代碼
此代碼的問題是
ASP 和 Visual Basic 使用的字符串數據類型(BSTR 或 Basic 字符串)實際上無法更改長度
這意味著每當字符串長度更改時
內存中字符串的原始表示形式都將遭到破壞
而且將創建一個包含新字符串數據的新的表示形式
這將增加分配內存和解除分配內存的操作
當然
ASP 和 Visual Basic 已為您解決了這一問題
因此實際開銷不會立即顯現出來
分配內存和解除分配內存要求基本運行時代碼解除各個專用鎖定
因此需要大量開銷
當字符串變得很大並且有大塊內存要被快速連續地分配和解除分配時
此問題變得尤為明顯
就像在大型字符串連接期間出現的情況一樣
盡管這一問題對單用戶環境的影響不大
但在服務器環境(例如
在 Web 服務器上運行的 ASP 應用程序)中
它將導致嚴重的性能和可縮放性問題
下面
我們回到上述代碼片段
此代碼中要執行多少個字符串分配操作?答案是
個
在這種情況下
&
運算符的每次應用都將導致變量 sHTML 所指的字符串被破壞和重新創建
前面已經提到
字符串分配的開銷很大
並且隨著字符串的增大而增加
因此
我們可以對上述代碼進行改進
快捷的解決方案 有兩種方法可以緩解字符串連接的影響
第一種方法是嘗試減小要處理的字符串的大小
第二種方法是嘗試減少執行字符串分配操作的數目
請參見下面所示的 WriteHTML 代碼的修訂版本
Function WriteHTML( Data )
Dim nRep
For nRep =
to
sHTML = sHTML & ( vbcrlf _
&
<TR><TD>
& (nRep +
) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD><TD>
_
& Data(
nRep ) &
</TD></TR>
)
Next
WriteHTML = sHTML
End Function
乍一看
可能很難發現這段代碼與上一個代碼示例的差別
其實
此代碼只是在 sHTML = sHTML & 後的內容外面加上了括號
這實際上是通過更改優先順序
來減小大多數字符串連接操作中處理的字符串大小
在最初的代碼示例中
ASP 編譯器將查看等號右邊的表達式
並從左到右進行計算
結果
每次重復都要進行
個連接操作
這些操作針對不斷增長的 sHTML 進行
在新版本中
我們提示編譯器更改操作順序
現在
它將按從左到右
從括號內到括號外的順序計算表達式
此技術使得每次重復包括
個連接操作
這些操作針對的是不會增長的較小字符串
只有一個是針對不斷增長的大的 sHTML
圖
顯示了這種優化方法與標准連接方法在內存使用模式方面的比較
educitycn/img_///jpg> 圖 標准連接與加括號連接在內存使用模式方面的比較 在特定情況下
使用括號可以對性能和可縮放性產生十分顯著的影響
後文將對此進行進一步的說明
StringBuilder
我們已經找到了解決字符串連接問題的快捷方法
在多數情況下
此方法可以達到性能和投入的最佳平衡
但是
如果要進一步提高構建大型字符串的性能
需要采用第二種方法
即減少字符串分配操作的數目
為此
需要使用 StringBuilder
StringBuilder 是一個類
用於維護可配置的字符串緩沖區
管理插入到此緩沖區的新文本片斷
並僅在文本長度超出字符串緩沖區長度時對字符串進行重新分配
Microsoft
NET 框架免費提供了這樣一個類 (System
Text
StringBuilder)
並建議在該環境下進行的所有字符串連接操作中使用它
在 ASP 和傳統的 Visual Basic 環境中
我們無法訪問此類
因此需要自行創建
下面是使用 Visual Basic
創建的 StringBuilder 類示例(為簡潔起見
省略了錯誤處理代碼)
Option Explicit
默認的緩沖區初始大小和增長系數
Private Const DEF_INITIALSIZE As Long =
Private Const DEF_GROWTH As Long =
緩沖區大小和增長
Private m_nInitialSize As Long
Private m_nGrowth As Long
緩沖區和緩沖區計數器
Private m_sText As String
Private m_nSize As Long
Private m_nPos As Long
Private Sub Class_Initialize()
設置大小和增長的默認值
m_nInitialSize = DEF_INITIALSIZE
m_nGrowth = DEF_GROWTH
初始化緩沖區
InitBuffer
End Sub
設置初始大小和增長數量
Public Sub Init(ByVal InitialSize As Long
ByVal Growth As Long)
If InitialSize >
Then m_nInitialSize = InitialSize
If Growth >
Then m_nGrowth = Growth
End Sub
初始化緩沖區
Private Sub InitBuffer()
m_nSize =
m_nPos =
End Sub
增大緩沖區
Private Sub Grow(Optional MinimimGrowth As Long)
初始化緩沖區(如有必要)
If m_nSize =
Then
m_nSize = m_nInitialSize
m_sText = Space$(m_nInitialSize)
Else
只是增長
Dim nGrowth As Long
nGrowth = IIf(m_nGrowth > MinimimGrowth
m_nGrowth
MinimimGrowth)
m_nSize = m_nSize + nGrowth
m_sText = m_sText & Space$(nGrowth)
End If
End Sub
將緩沖區大小調整到當前使用的大小
Private Sub Shrink()
If m_nSize > m_nPos Then
m_nSize = m_nPos
m_sText = RTrim$(m_sText)
End If
End Sub
添加單個文本字符串
Private Sub AppendInternal(ByVal Text As String)
If (m_nPos + Len(Text)) > m_nSize Then Grow Len(Text)
Mid$(m_sText
m_nPos
Len(Text)) = Text
m_nPos = m_nPos + Len(Text)
End Sub
添加一些文本字符串
Public Sub Append(ParamArray Text())
Dim nArg As Long
For nArg =
To UBound(Text)
AppendInternal CStr(Text(nArg))
Next nArg
End Sub
返回當前字符串數據並調整緩沖區大小
Public Function ToString() As String
If m_nPos >
Then
Shrink
ToString = m_sText
Else
ToString =
End If
End Function
清除緩沖區並重新初始化
Public Sub Clear()
InitBuffer
End Sub
此類中使用的基本原則是
在類級別將變量 (m_sText) 用作字符串緩沖區
並使用 Space$ 函數以空格字符填充此緩沖區以將其設置為特定的大小
如果要將更多文本與現有文本連接在一起
則在檢查緩沖區的大小足以存放新文本後
使用 Mid$ 函數在正確位置插入文本
ToString 函數將返回當前存儲在緩沖區中的文本
並將緩沖區的大小調整為能夠容納此文本的正確長度
使用 StringBuilder 的 ASP 代
From:http://tw.wingwit.com/Article/program/net/201311/12940.html