循环中基于任务的异步模式

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()
...