【发布时间】:2014-11-10 12:22:06
【问题描述】:
我正在返回大量 DataTable 行,对其进行迭代并将每行的值推送到 Web 服务,然后返回响应代码(字符串)。如果 webservice 出现任何错误,整个过程将停止并显示错误:
Protected Sub DoStuff(sender As Object, e As EventArgs) Handles lnk_orderCards.Click
Dim dt as DataTable = GetDataBaseData()
For each dr as DataRow in dt.Rows()
Dim f as String = dr.Item("firstname").ToString()
Dim m as String = dr.Item("middleName").ToString()
Dim s as String = dr.Item("surname").ToString()
Dim err as String = String.Empty
Dim result as String = XYZService.DoIt(f, m, s)
Select Case result
Case "ok"
' OK - allow For Loop Next '
Case "e"
err = "Some error"
Case "e2"
err = "Another error"
End Select
If Not String.IsNullOrWhiteSpace(err) Then
ShowError(err)
Exit Sub
End If
Next
XYZService.Complete()
ltl_status.Text = "Success!"
End Sub
我认为上述方法非常适合异步方法,尤其是在数据表有 1000 行的情况下,因为每个 Web 服务请求都可以并行发送。但是,从 MSDN 中,我找不到足够的示例来说明如何最好地实现异步。
谁能推荐一个更彻底的方法?我在MSDN 上阅读过关于Task.WaitAll 和Task.Factory.StartNew 的内容,但这些示例并不简单。如果使用Task.WaitAll like this,如果一个(或多个)任务失败,你如何停止流程?
重要的是,在调用XYZService.Complete() 之前,所有任务都返回成功。
基于 Stephen 输入的最终代码
Protected Async Sub DoStuff(sender As Object, e As EventArgs) Handles lnk_orderCards.Click
Dim cts As New CancellationTokenSource
Dim dt As DataTable = GetDataBaseData()
Dim rows As IEnumerable(Of Task(Of String)) = (From dr As DataRow In dt.Rows Select DoServiceCall(cts, dr))
Dim results() As String = Await Task.WhenAll(rows)
Dim errors As List(Of String) = (From s As String In results Where s <> String.Empty).ToList()
If errors.Count > 0 Then
ShowError(String.Join("<br/>", errors))
Exit Sub
Else
Console.WriteLine("Success")
End If
End Sub
Protected Async Function DoServiceCall(t As CancellationTokenSource, dr As DataRow) As Task(Of String)
If t.IsCancellationRequested Then
t.Token.ThrowIfCancellationRequested()
End If
Dim f As String = dr.Item("firstname").ToString()
Dim m As String = dr.Item("middleName").ToString()
Dim s As String = dr.Item("surname").ToString()
Dim returnResult As XYZService.ServiceReturnResult = Await XYZService.DoItAsync(f, s, s)
Select Case returnResult.return
Case "ok"
' OK - allow For Loop Next '
Case Else
t.Cancel(False)
Throw New Exception("Web service error: " & returnResult.return)
End Select
Return returnResult.return
End Function
【问题讨论】:
-
async/await 将不会并行执行任何操作。但是,它将允许 GUI 在等待时保持响应。如果要并行执行,请使用
Task.Factory.StartNew。 -
然后我读到 ASP.Net 中的
StartNew是一个非常糟糕的主意 (bit.ly/1ueSZeG) 并且没有正确记录替代方案,整个事情只是变得更加混乱... :-/ -
一劳永逸是个坏主意。如果您并行启动 100 个任务并等待它们,这不是“一劳永逸”。 (这仍然是一种可能的 DoS,因为一个请求会产生大量工作)
-
@DasKrümelmonster 这并不完全正确,而
async本身并不会导致方法神奇地异步执行,在点击第一个await时,代码可能在不同的同步上下文中运行,因此,不同的线程。
标签: asp.net .net vb.net asynchronous asp.net-4.5