12.2异步执行命令
来源:优易学  2010-1-12 12:03:06   【优易学:中国教育考试门户网】   资料下载   IT书店

 

在上述范例中我们先编写了符合 AsyncCallback Delegate 类所定的函数签名(signature)的回调函数 HandleAsyncCallBack,在主线程通过以下语法转交工作线程做数据库查询时,一并告知当查询完毕获得结果后,工作线程要执行的回调函数。

.BeginExecuteReader(New AsyncCallback(AddressOf HandleAsyncCallBack), Nothing)

当工作线程取回执行结果后,会直接执行 HandleAsyncCallBack。若如上述范例需要更新画面,这通常要主线程来完成,否则会造成多条线程抢资源,而 .NET Windows Form 和控制项为了性能并未提供多线程同步的机制,多条线程同时执行相同的程序代码,将导致变量内容中的数据结构错乱。因此在回调函数中通过以下的语法将更新画面的工作交回主线程执行:

Me.Invoke(New PopulateList(AddressOf ListProducts), dRead)

上述通过回调函数执行异步的工作是最常使用的机制。接着,我们再以等待同步对象收到通知机制编写另一个程序代码范例。程序画面如图12-4 所示:

图12-4 异步同时执行并等待三个查询结果

在这个程序范例中,我们模拟同时访问不同的数据源,因为能够简单地在同一台机器上测试,所以仅同时访问 AdventureWorks 范例数据库上的三个数据表。但在真实世界中,你可能是从不同的数据库服务器中各自取得相关的记录,而有些环境执行比较快,另一些环境较没有效率,因此数据会先后取得。这时可以 WaitHandle 类的静态方法 WaitAny 将先取得的结果先处理,后返回的结果后处理。程序代码范例如列表12-4所示:

程序代码列表12-4 以 WaitHandle 对象等待执行完毕后再更新画面

Button1.Enabled = False

Dim strDelay(2) As String

Dim cmd(2) As SqlCommand

Dim hdl(2) As System.Threading.WaitHandle

Dim dgv() As DataGridView = {DataGridView1, DataGridView2, DataGridView3}

Dim ar(2) As IAsyncResult

Dim dr(2) As SqlDataReader

Dim dt(2) As System.Data.DataTable

Dim rnd As New Random

Dim i As Integer

Label1.Text = "三个查询分别等待 "

Dim strCnn As String = _

ConfigurationSettings.ConnectionStrings("AWConnectionString").ConnectionString

Using cnn As New SqlConnection(strCnn), cnn1 As New SqlConnection(strCnn), _

cnn2 As New SqlConnection(strCnn)

For i = 0 To 2

strDelay(i) = rnd.Next(1, 5).ToString()

Label1.Text &= strDelay(i).ToString() & ","

'查询时分别让 SQL Server 等待一段随机数时间,以模拟不同的执行性能

strDelay(i) = "WAITFOR DELAY '00:00:0" & strDelay(i) & "'"

cmd(i) = New SqlCommand()

dt(i) = New System.Data.DataTable()

dgv(i).DataSource = Nothing

Next i

Label1.Text = Label1.Text.Substring(0, Label1.Text.Length - 1) & " 秒。"

Me.Refresh()

With cmd(0)

.CommandText = strDelay(0) & _

" SELECT TOP 1000 CustomerID,SalesPersonID,CustomerType FROM Sales.Customer"

.Connection = cnn

cnn.Open()

'非同步执行,并取回同步对象 WaitHandle

ar(0) = .BeginExecuteReader()

hdl(0) = ar(0).AsyncWaitHandle

End With

With cmd(1)

.CommandText = strDelay(1) & _

" SELECT TOP 1000 SalesOrderID,OrderDate,CustomerID FROM Sales.SalesOrderHeader"

.Connection = cnn1

cnn1.Open()

ar(1) = .BeginExecuteReader()

hdl(1) = ar(1).AsyncWaitHandle

End With

With cmd(2)

.CommandText = strDelay(2) & _

" SELECT TOP 1000 SalesOrderID,ProductID,LineTotal FROM Sales.SalesOrderDetail"

.Connection = cnn2

cnn2.Open()

ar(2) = .BeginExecuteReader()

hdl(2) = ar(2).AsyncWaitHandle

End With

Dim iHdl As Integer

'当三个查询中有一个完成时,就让主线程先更新该 Handle 所代表的查询

For i = 0 To 2

iHdl = System.Threading.WaitHandle.WaitAny(hdl, 5000, False)

If (System.Threading.WaitHandle.WaitTimeout = iHdl) Then

'Throw New Exception("等待超过 5 秒钟都没有任何查询返回")

MessageBox.Show("等待超过 5 秒钟都没有任何查询返回")

Exit For

End If

'取回查询结果所形成的 SqlDataReader

dr(iHdl) = cmd(iHdl).EndExecuteReader(ar(iHdl))

'直接通过 SqlDataReader 将记录装载到 DataTable

dt(iHdl).Load(dr(iHdl))

dgv(iHdl).DataSource = dt(iHdl)

Label1.Text &= iHdl.ToString() & " 返回 "

'更新画面

Me.Refresh()

Next

For i = 0 To 2

If Not dr(i) Is Nothing AndAlso Not dr(i).IsClosed Then dr(i).Close()

'hdl(i).Close()

Next

End Using

Button1.Enabled = True

 

上一页  [1] [2] [3] [4] 下一页

责任编辑:cyth

文章搜索:
 相关文章
热点资讯
热门课程培训