Web開發中使用多線程可以增強用戶體驗尤其是多用戶多任務海量數據和資源緊張的情況下下面這些代碼范例都是入門級的希望對對大家學習ASPNet多線程編程有所幫助
使用多線程是為了提高CPU的利用率即在在相同的時間裡面做更多的事情(但前提是系統資源沒有完全耗盡)ASPNET中使用多線程可以加快頁面在服務器端的生成速度一般頁面生成過程中花費時間最多的是數據庫查詢階段如果你的頁面有個查詢不使用多線程的話這個查詢將是串行執行的——即依次執行每一個查詢如果使用多線程將可以使這個查詢幾乎同時執行這顯然會提高頁面的生成速度
在網上搜索了些許帖子說在IIS進程中使用多線程是不穩定的可我經過實踐卻發現ASPNET使用多線程也沒出啥問題不過在ASPNET中使用多線程得注意一些地方不然確實是不穩定甚至是行不通的比如不能在多線程中使用HttpContext下的任何方法和屬性這就包括CookieSessionResponseRequestApplication等等當使用這些方法或者屬性的時候IIS進程將會直接崩潰更要注意的是由於多線程與頁面的加載(Load)是異步執行的必須讓這些創建的線程在Load執行完之前同步不然可能導致數據沒有加載成功 可能會有人問HttpContext等都被限制了頁面中還能做什麼呢?我們完全可以把創建的線程與頁面主體隔開把需要的數據先在頁面主體中獲取然後直接傳入到創建的線程中就可解決話不多說具體如何請看下文
假設某個頁面中有個SQL查詢一個是根據Url傳遞來的參數P確定當前頁的內容另一個查詢是顯示所有分類第一個查詢語句需要用到RequestQueryString獲取P傳遞來的頁碼第二個查詢語句則可直接寫SQL語句
假設第一個查詢語句如SELECT * FROM Archives WHERE Page=傳遞的頁碼
假設第二個查詢語句如SELECT * FROM Category
我們先創建一個類用於接受參數P和數據綁定控件ID(此處使用Repeater控件綁定數據)此類能夠把SQL語句查詢的結果綁定到數據控件(Repeater)中
public classBindData
{
private int currentPage = ;
private Repeater rpID;
public BindData(Repeater rpID)
{
thisrpID = rpID;
}
public BindData(Repeater rpIDint page)
{
thisrpID = rpID;
thiscurrentPage = page;
}
public void BindCategory()
{
string strSql=SELECT * FROM Category;
thisBindDataToRepeater(strSql thisrpID);
}
public void BindArchive()
{
string strSql = stringFormat(SELECT * FROM Archives WHERE Page={}thiscurrentPage);
thisBindDataToRepeater(strSql thisrpID);
}
private void BindDataToRepeater(string strSql Repeater rp)
{
if (rp == null) return;
SqlConnection conn = new SqlConnection(data source=數據服務器地址;User ID=用戶名;pwd=密碼;Initial Catalog=數據庫名);
SqlCommand cmd = new SqlCommand(strSql conn);
SqlDataReader dtr;
try
{
connOpen();
dtr = cmdExecuteReader();
controlIDDataSource = rp;
controlIDDataBind();
if (!dtrIsClosed)
dtrClose();
}
catch { }
finally
{
cmdDispose();
if (connState = ConnectionStateOpen)
connClose();
}
}
}
上面創建的BindData類中有個構造函數分別用於綁定分類綁定Arhive的不同形式如果使用其他數據綁定控件則可進行相應修改
創建了個私有方法BindDataToRepeater用於把對應的SQL語句查詢的結果綁定到對應的Repeater控件上同時在此方法中使用了SqlDataReader以提高綁定數據的速度如果你使用了數據工廠可修改BindDataToRepeater中的具體實現過程
個共有方法BindCategory和BindArchive分別用於創建不同SQL語句設置Repater的ID
同時需要引入SystemWebUISystemWebUIHtmlControlsSystemDataSqlClient個必要的命名空間
值得注意的是在BindDataToRepeater方法中使用了trycatch語句但並沒有在catch塊中做任何事情為什麼我們用trycatch卻不在catch塊中做點什麼事情呢不是多此一舉嗎?使用trycatch是為了防止在執行BindDataToRepeater時拋出異常若此處出現異常且此方法是在多線程中執行的將會導致IIS進程崩潰進而影響其他頁面的正常執行故而用trycatch防止BindDataToRepeater拋出錯誤
我們之所以為數據綁定創建一個類是為了提高內存利用率當數據加載(Load)完畢的時候為這個類創建的實例就會銷毀我們也可以通過在頁面中創建幾個全局變量來實現但我還是建議以類的形式傳遞數據而不是使用全局變量下面我們開始在頁面的Load中創建線程了首先你需要在頁面中引入SystemThreading命名空間
public classBindData
{
private int currentPage = ;
private Repeater rpID;
public BindData(Repeater rpID)
{
thisrpID = rpID;
}
public BindData(Repeater rpIDint page)
{
thisrpID = rpID;
thiscurrentPage = page;
}
public void BindCategory()
{
string strSql=SELECT * FROM Category;
thisBindDataToRepeater(strSql thisrpID);
}
public void BindArchive()
{
string strSql = stringFormat(SELECT * FROM Archives WHERE Page={}thiscurrentPage);
thisBindDataToRepeater(strSql thisrpID);
}
private void BindDataToRepeater(string strSql Repeater rp)
{
if (rp == null) return;
SqlConnection conn = new SqlConnection(data source=數據服務器地址;User ID=用戶名;pwd=密碼;Initial Catalog=數據庫名);
SqlCommand cmd = new SqlCommand(strSql conn);
SqlDataReader dtr;
try
{
connOpen();
dtr = cmdExecuteReader();
controlIDDataSource = rp;
controlIDDataBind();
if (!dtrIsClosed)
dtrClose();
}
catch { }
finally
{
cmdDispose();
if (connState = ConnectionStateOpen)
connClose();
}
}
}
上面的代碼顯示在!IsPostBack狀態下綁定數據利用RequestQueryString獲取了當前頁碼並創建了BindData的個實例LoadArchivesLoadCategory通過 Thread thArhives=new Thread(new ThreadStart(LoadArchivesBindArchive))為綁定Arhice創建線程通過Thread thCategory = new Thread(new ThreadStart(LoadCategoryBindCategory))為綁定分類創建線程同時調用Thread的Start方法使個線程進入執行狀態最後在Load的最下面用Thread的Join方法使創建的個線程與頁面加載同步
值得注意的是Join方法是必須的如果不使用可能導致創建的線程還未把數據完全綁定到Repeater上Load就已經執行完畢若如此頁面上將沒有任何數據同時調用Start的代碼行應盡量早調用Join的代碼行都應盡量遲——盡量放在Page_Load代碼段的末尾這樣才能達到多線程的目的若你每調用一個Start馬上調用Join其實質和沒有使用多線程的效果是一樣的Join在MSND上的解釋是在繼續執行標准的 COM 和 SendMessage 消息泵處理期間阻塞調用線程直到某個線程終止為止
只要設置好ASPX頁面Repeater的綁定項數據就可成功加載了上面僅僅展示了個SQL語句的查詢如果你有個或者更多的SQL查詢在Page_Load中創建個線程讓他們異步執行最後用Join同步到Load是一個提高性能的不錯方法
From:http://tw.wingwit.com/Article/program/net/201311/12820.html