(据说)异步查询等待结果

时间:2018-11-30 13:12:35

标签: vb.net asynchronous

我的目的是查询一个远程数据库,查询许多(最多5000个)表中的一个(但每个表都不同)字段:

SELECT FOO FROM TABLEA WHERE ...
SELECT BAR FROM TABLEB WHERE ...

到目前为止,使用的代码是:

Public Class ValuesRepository
    Private connectionString As String
    Private BatchOdbcConnection As IDbConnection

    Public Sub New(connectionString As String)
        Me.connectionString = connectionString
        BatchOdbcConnection = New Odbc.OdbcConnection("DRIVER={AspenTech ODBC driver for Production Record Manager};" + connectionString)
    End Sub

    PublicFunction GetAllBatchValues(tagList As IEnumerable(Of BatchTag)) As IEnumerable(Of IEnumerable(Of Double?))
        Dim returnList As New List(Of IEnumerable(Of Double?))
        If tagList.Count = 0 Then Return returnList
        BatchOdbcConnection.Open()
        For Each batchTag In tagList
            Dim result As Double? = GetBatchList(batchTag.fieldName, batchTag.tableName)
            If result Is Nothing Then
                Continue For
            Else
                returnList.Add(result.Value)
            End If
        Next
        BatchOdbcConnection.Close()
        Return returnList
    End Function

    Private Function GetBatchList(fieldName As String, tableName As String) As IEnumerable(Of Double?)
        Const SQLQuery As String = "SELECT ""{0}"" FROM ""{1}"";"

        Dim query = String.Format(SQLQuery,
                                  fieldName,
                                  tableName)
        Dim queryResult = BatchOdbcConnection.Query(Of Double?)(query, commandType:=CommandType.Text)
        Return queryResult
    End Function
End Class

我已经分析了代码,多达70%的时间是花在Dapper的Query方法上,这效率很低。

我一直在尝试通过使其全部异步来改善此问题,以便在完成查询之前启动下一个查询:

Public Class ValuesRepository
    Private connectionString As String

    Public Sub New(connectionString As String)
        Me.connectionString = connectionString
    End Sub

    Private Function GetOdbcConnection() As IDbConnection
        Return New Odbc.OdbcConnection("DRIVER={AspenTech ODBC driver for Production Record Manager};" + connectionString)
    End Function

    Public Function GetAllBatchValues(tagList As IEnumerable(Of BatchTag)) As IEnumerable(Of IEnumerable(Of Double))
        Dim returnList As New List(Of IEnumerable(Of Double?))
        If tagList.Count = 0 Then Return returnList

        Dim tasks As New List(Of Task(Of IEnumerable(Of Double?)))

        For Each batchTag In tagList
            tasks.Add(GetBatchList(batchTag.fieldName, batchTag.tableName))
        Next

        Task.WaitAll(tasks.ToArray())

        For Each task In tasks
            Dim result = task.Result
            If result Is Nothing Then
                Continue For
            Else
                returnList.Add(result.Value)
            End If
        Next
        Return returnList
    End Function

    Private Async Function GetBatchList(fieldName As String, tableName As String) As Task(Of IEnumerable(Of Double?))
        Console.WriteLine("Begin " + fieldName + " -> " + tableName)
        Using conn = GetOdbcConnection()
            Const SQLQuery As String = "SELECT ""{0}"" FROM ""{1}"";"

            Dim query = String.Format(SQLQuery,
                                  fieldName,
                                  tableName)

            Dim queryResult = Await conn.QueryAsync(Of Double?)(query, commandType:=CommandType.Text)
            Console.WriteLine("End " + fieldName + " -> " + tableName)
            Return queryResult
        End Using
    End Function
End Class

我曾期望它会启动所有查询,然后等待结果,并因此在控制台中读取如下内容:

Begin: Foo -> TableA
Begin: Bar -> TableB
...
End: Bar -> TableB
End: Foo-> TableA

相反,控制台显示:

Begin: Foo -> TableA
End: Foo-> TableA
Begin: Bar -> TableB

从时序上很明显,应用程序实际上正在等待每次调用后查询结束。

我在做什么错了?

1 个答案:

答案 0 :(得分:0)

尝试将Await conn.QueryAsync替换为Await Task.Delay,看看是否可行。如果它能正常工作,那么您会收到一个新问题“为什么Await conn.QueryAsync阻止所有活动任务?”。检查您的驱动程序版本是否支持异步调用。可能有一个叫做QueryAsync的方法,但是在后面,它调用了不支持Async的驱动程序。