【问题标题】:Async Await Wait for all the results and continueAsync Await 等待所有结果并继续
【发布时间】:2019-04-08 23:46:49
【问题描述】:

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

我想并行调用 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 正在警告我。 非常感谢。

【问题讨论】:

  • 为了Await您的任务而不是使用.WaitAll.Result,您需要将您的GetParseExpressionResults方法变成一个返回Task并具有Async的函数关键字,就像使用 GetParseExpression 一样。
  • (如果你做了我刚才提到的事情,那么你可以使用Await Task.WhenAll(...)Me.parseExpressionItemsTo = Await taskTo,例如。

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


【解决方案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 是异步的,所以我们知道它内部的某个地方有一个 await。事实上,如果您忘记在异步函数中等待,您的编译器会发出警告。

只要 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 来访问任务的等待返回值。

【讨论】:

    猜你喜欢
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-11
    相关资源
    最近更新 更多