【THICK】ASP.NET中常用的優化效能的方法

iDotNetSpace發表於2008-06-05

1.       資料庫訪問效能優化
      資料庫的連線和關閉
  訪問資料庫資源需要建立連線、開啟連線和關閉連線幾個操作。這些過程需要多次與資料庫交換資訊以通過身份驗證,比較耗費伺服器資源。ASP.NET中提供了連線池(Connection Pool)改善開啟和關閉資料庫對效能的影響。系統將使用者的資料庫連線放在連線池中,需要時取出,關閉時收回連線,等待下一次的連線請求。
  連線池的大小是有限的,如果在連線池達到最大限度後仍要求建立連線,必然大大影響效能。因此,在建立資料庫連線後只有在真正需要操作時才開啟連線,使用完畢後馬上關閉,從而儘量減少資料庫連線開啟的時間,避免出現超出連線限制的情況。 
       使用儲存過程
  儲存過程是儲存在伺服器上的一組預編譯的SQL語句,類似於DOS系統中的批處理檔案。儲存過程具有對資料庫立即訪問的功能,資訊處理極為迅速。使用儲存過程可以避免對命令的多次編譯,在執行一次後其執行規劃就駐留在快取記憶體中,以後需要時只需直接呼叫快取中的二進位制程式碼即可。
  另外,儲存過程在伺服器端執行,獨立於ASP.NET程式,便於修改,最重要的是它可以減少資料庫操作語句在網路中的傳輸。
      優化查詢語句
ASP.NETADO連線消耗的資源相當大,SQL語句執行的時間越長,佔用系統資源的時間也越長。因此,儘量使用優化過的SQL語句以減少執行時間。比如,不在查詢語句中包含子查詢語句,充分利用索引等。

2.       字串操作效能優化
  使用值型別的ToString方法
  在連線字串時,經常使用"+"號直接將數字新增到字串中。這種方法雖然簡單,也可以得到正確結果,但是由於涉及到不同的資料型別,數字需要通過裝箱操作轉化為引用型別才可以新增到字串中。但是裝箱操作對效能影響較大,因為在進行這類處理時,將在託管堆中分配一個新的物件,原有的值複製到新建立的物件中。
  使用值型別的ToString方法可以避免裝箱操作,從而提高應用程式效能。
  運用StringBuilder
  String類物件是不可改變的,對於String物件的重新賦值在本質上是重新建立了一個String物件並將新值賦予該物件,其方法ToString對效能的提高並非很顯著。
  在處理字串時,最好使用StringBuilder類,其.NET 名稱空間是System.Text。該類並非建立新的物件,而是通過AppendRemoveInsert等方法直接對字串進行操作,通過ToString方法返回操作結果。
  其定義及操作語句如下所示:

int num;
System.Text.StringBuilder str = new System.Text.StringBuilder(); //建立字串
str.Append(num.ToString()); //新增數值num
Response.Write(str.ToString); //顯示操作結果


3.       優化 Web 伺服器計算機和特定應用程式的配置檔案以符合您的特定需要
  預設情況下,ASP.NET 配置被設定成啟用最廣泛的功能並儘量適應最常見的方案。因此,應用程式開發人員可以根據應用程式所使用的功能,優化和更改其中的某些配置,以提高應用程式的效能。下面的列表是您應該考慮的一些選項。
  僅對需要的應用程式啟用身份驗證。預設情況下,身份驗證模式為 Windows,或整合 NTLM。大多數情況下,對於需要身份驗證的應用程式,最好在 Machine.config 檔案中禁用身份驗證,並在 Web.config 檔案中啟用身份驗證。
  根據適當的請求和響應編碼設定來配置應用程式。ASP.NET 預設編碼格式為 UTF-8。如果您的應用程式為嚴格的 ASCII,請配置應用程式使用 ASCII 以獲得稍許的效能提高。
  考慮對應用程式禁用 AutoEventWireup。在 Machine.config 檔案中將 AutoEventWireup 屬性設定為 false,意味著頁面不將方法名與事件進行匹配和將兩者掛鉤(例如 Page_Load)。如果頁面開發人員要使用這些事件,需要在基類中重寫這些方法(例如,需要為頁面載入事件重寫 Page.OnLoad,而不是使用 Page_Load 方法)。如果禁用 AutoEventWireup,頁面將通過將事件連線留給頁面作者而不是自動執行它,獲得稍許的效能提升。
  從請求處理管線中移除不用的模組。預設情況下,伺服器計算機的 Machine.config 檔案中 節點的所有功能均保留為啟用。根據應用程式所使用的功能,您可以從請求管線中移除不用的模組以獲得稍許的效能提升。檢查每個模組及其功能,並按您的需要自定義它。
例如,如果您在應用程式中不使用會話狀態和輸出快取,則可以從 列表中移除它們,以便請求在不執行其他有意義的處理時,不必執行每個模組的進入和離開程式碼。 

4.       一定要禁用除錯模式
在部署生產應用程式或進行任何效能測量之前,始終記住禁用除錯模式。如果啟用了除錯模式,應用程式的效能可能受到非常大的影響。

5.       對於廣泛依賴外部資源的應用程式,請考慮在多處理器計算機上啟用網路園藝
ASP.NET 程式模型幫助啟用多處理器計算機上的可縮放性,將工作分發給多個程式(每個 CPU 一個),並且每個程式都將處理器關係設定為其 CPU。此技術稱為網路園藝。如果應用程式使用較慢的資料庫伺服器或呼叫具有外部依賴項的 COM 物件(這裡只是提及兩種可能性),則為您的應用程式啟用網路園藝是有益的。但是,在決定啟用網路園藝之前,您應該測試應用程式在網路園中的執行情況。

6.       只要可能,就快取資料和頁輸出
ASP.NET 提供了一些簡單的機制,它們會在不需要為每個頁請求動態計算頁輸出或資料時快取這些頁輸出或資料。另外,通過設計要進行快取的頁和資料請求(特別是在站點中預期將有較大通訊量的區域),可以優化這些頁的效能。與 .NET Framework 的任何 Web 窗體功能相比,適當地使用快取可以更好的提高站點的效能,有時這種提高是超數量級的。
使用 ASP.NET 快取機制有兩點需要注意。首先,不要快取太多項。快取每個項均有開銷,特別是在記憶體使用方面。不要快取容易重新計算和很少使用的項。其次,給快取的項分配的有效期不要太短。很快到期的項會導致快取中不必要的週轉,並且經常導致更多的程式碼清除和垃圾回收工作。若關心此問題,請監視與 ASP.NET Applications 效能物件關聯的 Cache Total Turnover Rate 效能計數器。高週轉率可能說明存在問題,特別是當項在到期前被移除時。這也稱作記憶體壓力。

7.       選擇適合頁面或應用程式的資料檢視機制
根據您選擇在 Web 窗體頁顯示資料的方式,在便利和效能之間常常存在著重要的權衡。例如,DataGrid Web 伺服器控制元件可能是一種顯示資料的方便快捷的方法,但就效能而言它的開銷常常是最大的。在某些簡單的情況下,您通過生成適當的 HTML 自己呈現資料可能很有效,但是自定義和瀏覽器定向會很快抵銷所獲得的額外功效。Repeater Web 伺服器控制元件是便利和效能的折衷。它高效、可自定義且可程式設計。

8.       SqlDataReader 類用於快速只進資料遊標
SqlDataReader 類提供了一種讀取從 SQL Server 資料庫檢索的只進資料流的方法。如果當建立 ASP.NET 應用程式時出現允許您使用它的情況,則 SqlDataReader 類提供比 DataSet 類更高的效能。情況之所以這樣,是因為 SqlDataReader 使用 SQL Server 的本機網路資料傳輸格式從資料庫連線直接讀取資料。另外,SqlDataReader 類實現 IEnumerable 介面,該介面也允許您將資料繫結到伺服器控制元件。有關更多資訊,請參見 SqlDataReader 類。有關 ASP.NET 如何訪問資料的資訊,請參見通過 ASP.NET 訪問資料。

9.       SQL Server 儲存過程用於資料訪問
.NET Framework 提供的所有資料訪問方法中,基於 SQL Server 的資料訪問是生成高效能、可縮放 Web 應用程式的推薦選擇。使用託管 SQL Server 提供程式時,可通過使用編譯的儲存過程而不是特殊查詢獲得額外的效能提高。
 
10.   避免單執行緒單元 (STA) COM 元件
預設情況下,ASP.NET 不允許任何 STA COM 元件在頁面內執行。若要執行它們,必須在 .aspx 檔案內將 ASPCompat=true 屬性包含在 @ Page 指令中。這樣就將執行用的執行緒池切換到 STA 執行緒池,而且使 HttpContext 和其他內建物件可用於 COM 物件。前者也是一種效能優化,因為它避免了將多執行緒單元 (MTA) 封送到 STA 執行緒的任何呼叫。
使用 STA COM 元件可能大大損害效能,應儘量避免。若必須使用 STA COM 元件,如在任何 interop 方案中,則應在執行期間進行大量呼叫並在每次呼叫期間傳送儘可能多的資訊。另外,小心不要在構造頁面期間建立任何 STA COM 元件。例如下面的程式碼中,在頁面構造時將例項化由某個執行緒建立的 MySTAComponent,而該執行緒並不是將執行頁面的 STA 執行緒。這可能對效能有不利影響,因為要構造頁面就必須完成 MTA STA 執行緒之間的封送處理。 


 
    Dim myComp as new MySTAComponent() 
    Public Sub Page_Load() 
        myComp.Name = "Bob" 
    End Sub


 
    Response.Write(myComp.SayHello)
%>

首選機制是推遲物件的建立,直到以後在 STA 執行緒下執行上述程式碼,如下面的例子所示。  



Dim myComp
Public Sub Page_Load()
myComp = new MySTAComponent()
myComp.Name = "Bob"
End Sub



Response.Write(myComp.SayHello)
%>


推薦的做法是在需要時或者在 Page_Load 方法中構造任何 COM 元件和外部資源。
永遠不要將任何 STA COM 元件儲存在可以由構造它的執行緒以外的其他執行緒訪問的共享資源裡。這類資源包括像快取和會話狀態這樣的資源。即使 STA 執行緒呼叫 STA COM 元件,也只有構造此 STA COM 元件的執行緒能夠實際為該呼叫服務,而這要求封送處理對建立者執行緒的呼叫。此封送處理可能產生重大的效能損失和可伸縮性問題。在這種情況下,請研究一下使 COM 元件成為 MTA COM 元件的可能性,或者更好的辦法是遷移程式碼以使物件成為託管物件。
11.   將呼叫密集型的 COM 元件遷移到託管程式碼
.NET Framework 提供了一個簡單的方法與傳統的 COM 元件進行互動。其優點是可以在保留現有投資的同時利用新的平臺。但是在某些情況下,保留舊元件的效能開銷使得將元件遷移到託管程式碼是值得的。每一情況都是不一樣的,決定是否需要遷移元件的最好方法是對 Web 站點執行效能測量。建議您研究一下如何將需要大量呼叫以進行互動的任何 COM 元件遷移到託管程式碼。
許多情況下不可能將舊式元件遷移到託管程式碼,特別是在最初遷移 Web 應用程式時。在這種情況下,最大的效能障礙之一是將資料從非託管環境封送到託管環境。因此,在互動操作中,請在任何一端執行儘可能多的任務,然後進行一個大呼叫而不是一系列小呼叫。例如,公共語言執行庫中的所有字串都是 Unicode 的,所以應在呼叫託管程式碼之前將元件中的所有字串轉換成 Unicode 格式。
另外,一處理完任何 COM 物件或本機資源就釋放它們。這樣,其他請求就能夠使用它們,並且最大限度地減少了因稍後請求垃圾回收器釋放它們所引起的效能問題。 
 
12.   Visual Basic .NET JScript. 程式碼中使用早期繫結
以往,開發人員喜歡使用 Visual BasicVBScript. JScript. 的原因之一就是它們所謂“無型別”的性質。變數不需要顯式型別宣告,並能夠簡單地通過使用來建立它們。當從一個型別到另一個型別進行分配時,轉換將自動執行。不過,這種便利會大大損害應用程式的效能。
Visual Basic 現在通過使用 Option Strict 編譯器指令來支援型別安全程式設計。為了向後相容,預設情況下,ASP.NET 不啟用該選項。但是,為了得到最佳效能,強烈建議在頁中啟用該選項。若要啟用 Option Strict,請將 Strict 屬性包括在 @ Page 指令中,或者,對於使用者控制元件,請將該屬性包括在 @ Control 指令中。下面的示例演示瞭如何設定該屬性,並進行了四個變數呼叫以顯示使用該屬性是如何導致編譯器錯誤的。 
 


Dim B
Dim C As String
' This will cause a compiler error.
A = "Hello"
' This will cause a compiler error.
B = "World"
' This will not cause a compiler error.
C = "!!!!!!"
' But this will cause a compiler error.
C = 0
%>

JScript. .NET 也支援無型別程式設計,但它不提供強制早期繫結的編譯器指令。若發生下面任何一種情況,則變數是晚期繫結的:
被顯式宣告為 Object
是無型別宣告的類的欄位。
是無顯式型別宣告的專用函式或方法成員,並且無法從其使用推斷出型別。
最後一個差別比較複雜,因為如果 JScript. .NET 編譯器可以根據變數的使用情況推斷出型別,它就會進行優化。在下面的示例中,變數 A 是早期繫結的,但變數 B 是晚期繫結的。 
 

var A;
var B; 
A = "Hello";
B = "World";
B = 0;


 
為了獲得最佳的效能,當宣告 JScript. .NET 變數時,請為其分配一個型別。例如,var A : String 
 
13.   使請求管線內的所有模組儘可能高效
請求管線內的所有模組在每次請求中都有機會被執行。因此,當請求進入和離開模組時快速地觸發程式碼至關重要,特別是在不使用模組功能的程式碼路徑裡。分別在使用及不使用模組和配置檔案時執行吞吐量測試,對確定這些方法的執行速度非常有用。

14.   使用 HttpServerUtility.Transfer 方法在同一應用程式的頁面間重定向
採用 Server.Transfer 語法,在頁面中使用該方法可避免不必要的客戶端重定向。 
 
15.   必要時調整應用程式每個輔助程式的執行緒數
ASP.NET 的請求結構試圖在執行請求的執行緒數和可用資源之間達到一種平衡。已知一個使用足夠 CPU 功率的應用程式,該結構將根據可用於請求的 CPU 功率,來決定允許同時執行的請求數。這項技術稱作執行緒門控。但是在某些條件下,執行緒門控演算法不是很有效。通過使用與 ASP.NET Applications 效能物件關聯的 Pipeline Instance Count 效能計數器,可以在 PerfMon 中監視執行緒門控。 

當頁面呼叫外部資源,如資料庫訪問或 XML Web services 請求時,頁面請求通常停止並釋放 CPU。如果某個請求正在等待被處理,並且執行緒池中有一個執行緒是自由的,那麼這個正在等待的請求將開始被處理。遺憾的是,有時這可能導致 Web 伺服器上存在大量同時處理的請求和許多正在等待的執行緒,而它們對伺服器效能有不利影響。通常,如果門控因子是外部資源的響應時間,則讓過多請求等待資源,對 Web 伺服器的吞吐量並無幫助。 
 
為緩和這種情況,可以通過更改 Machine.config 配置檔案 節點的 maxWorkerThreads maxIOThreads 屬性,手動設定程式中的執行緒數限制。
 
注意 輔助執行緒是用來處理 ASP.NET 請求的,而 IO 執行緒則是用於為來自檔案、資料庫或 XML Web services 的資料提供服務的。
分配給這些屬性的值是程式中每個 CPU 每類執行緒的最大數目。對於雙處理器計算機,最大數是設定值的兩倍。對於四處理器計算機,最大值是設定值的四倍。無論如何,對於有四個或八個 CPU 的計算機,最好更改預設值。對於有一個或兩個處理器的計算機,預設值就可以,但對於有更多處理器的計算機的效能,程式中有一百或兩百個執行緒則弊大於利。 
注意 程式中有太多執行緒往往會降低伺服器的速度,因為額外的上下文交換導致作業系統將 CPU 週期花在維護執行緒而不是處理請求上。 
 
16.   適當地使用公共語言執行庫的垃圾回收器和自動記憶體管理
小心不要給每個請求分配過多記憶體,因為這樣垃圾回收器將必須更頻繁地進行更多的工作。另外,不要讓不必要的指標指向物件,因為它們將使物件保持活動狀態,並且應儘量避免含 Finalize 方法的物件,因為它們在後面會導致更多的工作。特別是在 Finalize 呼叫中永遠不要釋放資源,因為資源在被垃圾回收器回收之前可能一直消耗著記憶體。最後這個問題經常會對 Web 伺服器環境的效能造成毀滅性的打擊,因為在等待 Finalize 執行時,很容易耗盡某個特定的資源。 
17.   如果有大型 Web 應用程式,可考慮執行預批編譯
每當發生對目錄的第一次請求時都會執行批編譯。如果目錄中的頁面沒有被分析並編譯,此功能會成批分析並編譯目錄中的所有頁面,以便更好地利用磁碟和記憶體。如果這需要很長時間,則將快速分析並編譯單個頁面,以便請求能被處理。此功能帶給 ASP.NET 效能上的好處,因為它將許多頁面編譯為單個程式集。從已載入的程式集訪問一頁比每頁載入新的程式集要快。
批編譯的缺點在於:如果伺服器接收到許多對尚未編譯的頁面的請求,那麼當 Web 伺服器分析並編譯它們時,效能可能較差。為解決這個問題,可以執行預批編譯。為此,只需在應用程式啟用之前向它請求一個頁面,無論哪頁均可。然後,當使用者首次訪問您的站點時,頁面及其程式集將已被編譯。 
 
沒有簡單的機制可以知道批編譯何時發生。需一直等到 CPU 空閒或者沒有更多的編譯器程式(例如 csc.exeC# 編譯器)或 vbc.exeVisual Basic 編譯器))啟動。 
 
還應儘量避免更改應用程式的 \bin 目錄中的程式集。更改頁面會導致重新分析和編譯該頁,而替換 \bin 目錄中的程式集則會導致完全重新批編譯該目錄。 
 
在包含許多頁面的大規模站點上,更好的辦法可能是根據計劃替換頁面或程式集的頻繁程度來設計不同的目錄結構。不常更改的頁面可以儲存在同一目錄中並在特定的時間進行預批編譯。經常更改的頁面應在它們自己的目錄中(每個目錄最多幾百頁)以便快速編譯。 
 
Web 應用程式可以包含許多子目錄。批編譯發生在目錄級,而不是應用程式級。 
 
18.   不要依賴程式碼中的異常
因為異常大大地降低效能,所以您不應該將它們用作控制正常程式流程的方式。如果有可能檢測到程式碼中可能導致異常的狀態,請執行這種操作。不要在處理該狀態之前捕獲異常本身。常見的方案包括:檢查 null,分配給將分析為數字值的 String 一個值,或在應用數學運算前檢查特定值。下面的示例演示可能導致異常的程式碼以及測試是否存在某種狀態的程式碼。兩者產生相同的結果。 

try

       result = 100 / num;
}
catch (Exception e)

       result = 0;
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-332365/,如需轉載,請註明出處,否則將追究法律責任。

【THICK】ASP.NET中常用的優化效能的方法
請登入後發表評論 登入
全部評論

相關文章