异步等待等待所有结果并继续

时间:2018-11-05 15:33:07

标签: .net vb.net async-await task

对于如何实现异步等待方法并在继续操作之前等待结果,我有些困惑。

我想并行调用3个后端,并等待它们直到响应,然后获取结果并在内部分配它们。 像这样:

  Private Sub GetParseExpressionResults()
    If Not isParseExpressionSupported Then
        Return
    End If

    'Cleaning collections
    Me.parseExpressionItemsTo.Clear()
    Me.parseExpressionItemsCC.Clear()
    Me.parseExpressionItemsSubject.Clear()

    'Getting list of document ids
    Dim docIds As List(Of Integer) = DocumentsToSend.Select(Function(doc) doc.id).ToList()

    'Getting all the parse expression and then wait for them
    Dim taskTo As Threading.Tasks.Task(Of List(Of ParseExpressionItem)) = GetParseExpression(txtTo.Text, docIds)
    Dim taskCC As Threading.Tasks.Task(Of List(Of ParseExpressionItem)) = GetParseExpression(txtCC.Text, docIds)
    Dim taskSubject As Threading.Tasks.Task(Of List(Of ParseExpressionItem)) = GetParseExpression(txtSubject.Text, docIds)

    Threading.Tasks.Task.WaitAll(taskTo, taskCC, taskSubject)
    Me.parseExpressionItemsTo = taskTo.Result
    Me.parseExpressionItemsCC = taskCC.Result
    Me.parseExpressionItemsSubject = taskSubject.Result
End Sub

Private Async Function GetParseExpression(ByVal text As String, ByVal docIds As List(Of Integer)) As Threading.Tasks.Task(Of List(Of ParseExpressionItem))
    If String.IsNullOrEmpty(text) Then
        Return New List(Of ParseExpressionItem)
    End If

    Dim result As List(Of ParseExpressionItem) = ClientActiveSession.Session.getParseExpression(text, docIds)
    Return result
End Function

此代码的问题是等待语句。似乎无法使用它,因此在这种情况下,代码将同步运行,实际上VS向我发出警告。 预先非常感谢。

2 个答案:

答案 0 :(得分:1)

通常,如果您的过程调用了另一个过程,则必须等到另一个过程完成。

有时,在您调用的过程的最深处,线程必须空闲地等待另一个进程完成。例如,从数据库查询一些数据,将数据写入文件,从Internet上获取信息,所有线程都只能等待的进程。

async-await的整个思想是让线程做其他事情,而不是闲着等待。例如,线程可以进入调用堆栈,以查看其中一个调用者是否没有等待。

稍后,当等待的进程完成时,线程(或其他线程)将在等待之后继续处理语句。

这就是为什么您决定使用async-await的原因:如果您的过程必须等待另一个进程完成,则您的线程可以在过程中执行其他操作,或者在调用者的过程中执行语句

结构类似于(对不起,我的基本知识有点生锈,我会用C#来做,但是要点)

var taskDoIt = DoSomethingAsync(...)

// because I am not awaiting, the following statements are executed when DoSomethingAsync
// has to wait
DoSomethingElse();

// now I need the results of DosomethingAsync, so I'll await:
var result = await taskDoIt();

如果在我开始等待时DoSomethingAsync中的等待过程未完成,则线程将在调用后上移至调用堆栈以执行语句,直到看到等待为止。再次向上调用堆栈以查看是否有人 等不及。

在您的程序中,当您调用等待过程而不等待它们完成时,我们会看到此模式:

Dim taskTo As Threading.Tasks.Task(Of List(Of ParseExpressionItem)) =
    GetParseExpression(txtTo.Text, docIds)

因为GetParseExpression是异步的,所以我们知道其中的某个地方有一个等待对象。实际上,如果您忘记在异步函数中等待,编译器会警告您。

GetParseExpression等待时,您的过程将继续:

Dim taskCC As Threading.Tasks.Task(Of List(Of ParseExpressionItem)) =
    GetParseExpression(txtCC.Text, docIds)

直到我们再次等待。继续:

Dim taskSubject As Threading.Tasks.Task(Of List(Of ParseExpressionItem)) =
    GetParseExpression(txtSubject.Text, docIds)

直到现在我们还没有等待。任务的结果可能尚不可用。此时,您决定需要这三个函数的结果。

现在是重要的更改:在异步函数中,不要使用Task.WhaitAll,请使用Task.WhenAll

Task.WhenAll是一个值得期待的功能。如果您开始等待它,则该线程将进入调用堆栈,以查看调用者是否有事要做,就像它与任何等待函数一样。

await Threading.Tasks.Task.WhenAll(new Task[] {taskTo, taskCC, taskSubject});

(请翻译成VB)

完成所有三个任务后,可以使用属性Result访问任务的等待返回值。

答案 1 :(得分:-2)

我认为问题在于您没有开始实际的任务。
尝试从MDSN here中应用示例。

Dim tasks As New List(Of Task(Of Integer))()  

For i As Integer = 0 To 9
        Dim index As Integer = i
        tasks.Add(Task(Of Integer).Factory.StartNew(action, index)) 'Action would be your async funtion
    Next

Task.WaitAll(tasks.ToArray()
相关问题