首先使用MARS我們必須先在連線字串裡啟用「MultipleActiveResultSets=True」,再來,我們要啟用ADO.NET的非同步功能,我們也必須在連線字串裡加入「Asynchronous Processing=true」。
ADO.NET-Asyn.aspx
以下我們將介紹三種非同步的方式。<form id="form1" runat="server">
<div>
<asp:Button ID="Poll" runat="server" Text="輪詢(Poll)" />
<asp:Button ID="bntWait" runat="server" Text="等待-單一表(WaitHandle)" />
<br />
<asp:Button ID="bntHandles" runat="server" Text="等待-兩資料表(WaitHandle) + MARS" />
<br />
<br />
<asp:GridView ID="gvOrders" runat="server" Caption="Orders">
</asp:GridView>
<asp:GridView ID="gvOrderDetails" runat="server" Caption="Order Details">
</asp:GridView>
</div>
</form>
ADO.NET-Asyn.aspx.vb
Imports System.Data
Imports System.Data.SqlClient
Imports System.Configuration
Partial Class ADONET_Asyn
Inherits System.Web.UI.Page
'使用MARS
Dim conn As New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString)
Dim strSQL As String = "select top 5 Customers.CompanyName , Customers.ContactName , Orders.OrderID ,Orders.OrderDate , Orders.RequiredDate, Orders.ShippedDate from Orders, Customers where (Orders.CustomerID = Customers.CustomerID) order by Customers.CompanyName, Customers.ContactName"
Protected Sub Poll_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Poll.Click
Dim cmd As New SqlCommand
cmd.CommandText = strSQL
cmd.CommandType = CommandType.Text
cmd.Connection = conn
conn.Open()
'非同步結果
Dim asyncResult As IAsyncResult
'執行非同步
asyncResult = cmd.BeginExecuteReader
'非同步是否完成,不然停止1秒
While Not asyncResult.IsCompleted
System.Threading.Thread.Sleep(1000)
End While
Dim dr As SqlDataReader
'取回非同步資料
dr = cmd.EndExecuteReader(asyncResult)
gvOrders.DataSource = dr
gvOrders.DataBind()
conn.Close()
End Sub
Protected Sub bntWait_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles bntWait.Click
Dim cmd As New SqlCommand
cmd.CommandText = strSQL
cmd.CommandType = CommandType.Text
cmd.Connection = conn
conn.Open()
Dim asyncResult As IAsyncResult
'等待碼
Dim WHandle As System.Threading.WaitHandle
Dim dr As SqlDataReader
asyncResult = cmd.BeginExecuteReader
'取得非同步等待碼
WHandle = asyncResult.AsyncWaitHandle
'WaitOne,等待完成
If WHandle.WaitOne = True Then
dr = cmd.EndExecuteReader(asyncResult)
gvOrders.DataSource = dr
gvOrders.DataBind()
conn.Close()
End If
End Sub
Protected Sub bntHandles_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles bntHandles.Click
Dim cmd As New SqlCommand
cmd.CommandText = strSQL
cmd.CommandType = CommandType.Text
cmd.Connection = conn 'MARS
Dim odcmd As New SqlCommand
odcmd.CommandText = "select * from customers where companyName = 'Alfreds Futterkiste'"
odcmd.CommandType = CommandType.Text
odcmd.Connection = conn 'MARS
conn.Open() 'MARS: cmd, odcmd
'非同步處理
Dim orAsyncResult As IAsyncResult
Dim odAsyncResult As IAsyncResult
'等待碼陣列
Dim WHandles(1) As System.Threading.WaitHandle
Dim orDr As SqlDataReader
Dim odDr As SqlDataReader
'取得非同步結果
orAsyncResult = cmd.BeginExecuteReader
odAsyncResult = odcmd.BeginExecuteReader
'取得等待碼(WaitHandle)
WHandles(0) = orAsyncResult.AsyncWaitHandle
WHandles(1) = odAsyncResult.AsyncWaitHandle
'第一種:使用WaitAll
''等待全部「等待碼」完成
'System.Threading.WaitHandle.WaitAll(WHandles)
'orDr = cmd.EndExecuteReader(orAsyncResult)
'odDr = odcmd.EndExecuteReader(odAsyncResult)
'gvOrders.DataSource = orDr
'gvOrders.DataBind()
'gvOrderDetails.DataSource = odDr
'gvOrderDetails.DataBind()
'第二種:使用WaitAny
For i As Integer = 0 To 1
Dim WHIndex As Integer
WHIndex = System.Threading.WaitHandle.WaitAny(WHandles)
Select Case WHIndex
Case 0
orDr = cmd.EndExecuteReader(orAsyncResult)
gvOrders.DataSource = orDr
gvOrders.DataBind()
Case 1
odDr = odcmd.EndExecuteReader(odAsyncResult)
gvOrderDetails.DataSource = odDr
gvOrderDetails.DataBind()
End Select
Next
conn.Close()
End Sub
End Class
其實用心看,程式不難,而且與我們之前寫的ADO.NET程式還有點像。
輪詢(Poll)
我們先由輪詢(Poll)來看,由BeginExecuteReader來啟動非同步的動作,BeginExecuteReader會傳回一個IAsyncResult,然後判斷非同步是否完成(asyncResult.IsCompleted),如已經完成,使用EndExecuteReader(asyncResult)取回DataReader資料。等待(WaitHandle)
在等待方法裡,過程差不多,只是多了一個「等待碼(asyncResult.AsyncWaitHandle),而且改由這個等待碼來判斷非同步是否完成,再接下去完成後面的動作。而WaitHandle.WaitOne()會等待單一非同步行程完成或逾時,WaitAll()會等待所有非同步過程結束,WaitAny()需要以陣列管理一個以上的等待碼,而且你必須為每個想要處理的等待碼個別叫用。在第三個按鈕裡我們看出MARS加上非同步的實用性,你可以同時發出「多個」Query而不用擔心。
好消息,從 .NET Framework 4.5 RC 開始,這些方法不再需要連接字串中的 Asynchronous Processing=true。
回覆刪除http://msdn.microsoft.com/zh-tw/library/hh211418.aspx
謝謝提供那麼棒的資訊。
刪除