循环中基于任务的异步模式
Task based Asynchronous Patterns in Loops
我需要将 BuildReports() 设为异步,因为此函数可能需要几分钟才能完成,具体取决于它必须创建的报告数量。它由 btnClearAll_Click() 调用,我也添加了“Async”和“Await”。我已将“Async”添加到 BuildReports() 并尝试了多个“等待”位置,包括在循环之前使用 If-Then-Else 语句。我还为在 reportComponent.CreatePDF() 中创建的数据表 (dt) 尝试了“Awaitable”(一个 SQL Select 查询)。 ClearAll() 是同步的。
所以我在这里需要一些帮助,我已经阅读了很多关于这方面的文章,但我遗漏了一些东西。任何指导将不胜感激。
Private Async Sub btnClearAll_Click(sender As Object, e As System.EventArgs) Handles btnClearAll.Click
Await BuildReports()
ClearAll()
End Sub
Private Async Function BuildReports() As Task
Try
Dim reportComponent As New ReportComponent(CStr(Session("UserConnectionString")))
Dim dt As New DataTable
dt = reportComponent.CreatePDF()
If dt IsNot Nothing Then
Dim ScheduleDto As New ScheduleDto()
Dim scheduleDtoList As New List(Of ScheduleDto)()
Dim report1 As Telerik.Reporting.Report = Nothing
For Each row As DataRow In dt.Rows
For i As Integer = 0 To dt.Rows.Count - 1
If row IsNot Nothing Then
ScheduleDto.Encounter_code = dt.Rows.Item(i).Item("Encounter_code").ToString
ScheduleDto.CaseNumber = dt.Rows.Item(i).Item("CaseNumber").ToString
ScheduleDto.Case_Name = dt.Rows.Item(i).Item("Case_Name").ToString
ScheduleDto.DOS = dt.Rows.Item(i).Item("DOS").ToString
ScheduleDto.Provider = dt.Rows.Item(i).Item("Provider").ToString
ScheduleDto.Discipline = dt.Rows.Item(i).Item("Discipline").ToString
ScheduleDto.Episode = dt.Rows.Item(i).Item("Episode").ToString
ScheduleDto.ReportType = dt.Rows.Item(i).Item("ReportType").ToString
ScheduleDto.DocumentName = dt.Rows.Item(i).Item("Document_Name").ToString
ScheduleDto.ItemType = dt.Rows.Item(i).Item("ItemType").ToString
scheduleDtoList.Add(ScheduleDto)
report1 = reportComponent.GetReport(ScheduleDto, ScheduleDto.ReportType, CStr(Session("UserConnectionString")))
If (report1 IsNot Nothing) Then
Dim pdfPath As String = ""
Dim DownloadReport As New DownloadReports()
DownloadReport.DownloadReport(report1, ScheduleDto, ScheduleDto.DocumentName, ScheduleDto.ReportType, pdfPath)
reportComponent.FinalizeNow(ScheduleDto.Encounter_code)
End If
End If
Next
Next
Else : Return
End If
Catch ex As SqlException
Throw New Exception(ex.Message & " : Build_Reports")
Finally
End Try
End Function
编译器应该为您提供该代码的错误,因为 BuildReports
被标记为 Async
但未使用 Await
.
请注意 "asynchronous" 不是 的意思 "run on a background thread"。于是,"make"同步代码就没办法异步了;代码本身本质上是同步或异步的。
因此,例如,如果您有自然异步的数据库操作(例如,使用 Entity Framework),那么您可以有自然异步的 BuildReports
。但是,DataTable
API 不适合异步,因此 DataTable
根本没有异步 API。它牢牢地卡在了同步世界中。
在您的特定情况下,最好 运行 您现有的 同步 代码在后台线程上,这可以通过 Task.Run
完成。然后你可以异步消费它:
Private Async Sub btnClearAll_Click(sender As Object, e As System.EventArgs) Handles btnClearAll.Click
Await Task.Run(Function() BuildReports())
ClearAll()
End Sub
Private Sub BuildReports()
...
我需要将 BuildReports() 设为异步,因为此函数可能需要几分钟才能完成,具体取决于它必须创建的报告数量。它由 btnClearAll_Click() 调用,我也添加了“Async”和“Await”。我已将“Async”添加到 BuildReports() 并尝试了多个“等待”位置,包括在循环之前使用 If-Then-Else 语句。我还为在 reportComponent.CreatePDF() 中创建的数据表 (dt) 尝试了“Awaitable”(一个 SQL Select 查询)。 ClearAll() 是同步的。
所以我在这里需要一些帮助,我已经阅读了很多关于这方面的文章,但我遗漏了一些东西。任何指导将不胜感激。
Private Async Sub btnClearAll_Click(sender As Object, e As System.EventArgs) Handles btnClearAll.Click
Await BuildReports()
ClearAll()
End Sub
Private Async Function BuildReports() As Task
Try
Dim reportComponent As New ReportComponent(CStr(Session("UserConnectionString")))
Dim dt As New DataTable
dt = reportComponent.CreatePDF()
If dt IsNot Nothing Then
Dim ScheduleDto As New ScheduleDto()
Dim scheduleDtoList As New List(Of ScheduleDto)()
Dim report1 As Telerik.Reporting.Report = Nothing
For Each row As DataRow In dt.Rows
For i As Integer = 0 To dt.Rows.Count - 1
If row IsNot Nothing Then
ScheduleDto.Encounter_code = dt.Rows.Item(i).Item("Encounter_code").ToString
ScheduleDto.CaseNumber = dt.Rows.Item(i).Item("CaseNumber").ToString
ScheduleDto.Case_Name = dt.Rows.Item(i).Item("Case_Name").ToString
ScheduleDto.DOS = dt.Rows.Item(i).Item("DOS").ToString
ScheduleDto.Provider = dt.Rows.Item(i).Item("Provider").ToString
ScheduleDto.Discipline = dt.Rows.Item(i).Item("Discipline").ToString
ScheduleDto.Episode = dt.Rows.Item(i).Item("Episode").ToString
ScheduleDto.ReportType = dt.Rows.Item(i).Item("ReportType").ToString
ScheduleDto.DocumentName = dt.Rows.Item(i).Item("Document_Name").ToString
ScheduleDto.ItemType = dt.Rows.Item(i).Item("ItemType").ToString
scheduleDtoList.Add(ScheduleDto)
report1 = reportComponent.GetReport(ScheduleDto, ScheduleDto.ReportType, CStr(Session("UserConnectionString")))
If (report1 IsNot Nothing) Then
Dim pdfPath As String = ""
Dim DownloadReport As New DownloadReports()
DownloadReport.DownloadReport(report1, ScheduleDto, ScheduleDto.DocumentName, ScheduleDto.ReportType, pdfPath)
reportComponent.FinalizeNow(ScheduleDto.Encounter_code)
End If
End If
Next
Next
Else : Return
End If
Catch ex As SqlException
Throw New Exception(ex.Message & " : Build_Reports")
Finally
End Try
End Function
编译器应该为您提供该代码的错误,因为 BuildReports
被标记为 Async
但未使用 Await
.
请注意 "asynchronous" 不是 的意思 "run on a background thread"。于是,"make"同步代码就没办法异步了;代码本身本质上是同步或异步的。
因此,例如,如果您有自然异步的数据库操作(例如,使用 Entity Framework),那么您可以有自然异步的 BuildReports
。但是,DataTable
API 不适合异步,因此 DataTable
根本没有异步 API。它牢牢地卡在了同步世界中。
在您的特定情况下,最好 运行 您现有的 同步 代码在后台线程上,这可以通过 Task.Run
完成。然后你可以异步消费它:
Private Async Sub btnClearAll_Click(sender As Object, e As System.EventArgs) Handles btnClearAll.Click
Await Task.Run(Function() BuildReports())
ClearAll()
End Sub
Private Sub BuildReports()
...