Async Await Wait for all the results and continue

无人久伴 提交于 2021-01-07 01:24:34

问题


I'm a bit confuse about how to implement async await approach and wait for results before continuing.

I want to make 3 calls to backend in parallel and wait for them until they responds then get the result and assign them internally. Something like this:

  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

The problem with this code is await sentence. It seems is not possible to use it and therefore in this case the code will run synchronously, in effect VS is warning me this. Many thanks in advance.


回答1:


Normally if your procedure calls another procedure it has to wait until this other procedure is finished.

Sometimes, deep inside the procedure that you called, the thread has to wait idly for another process to finish. Examples are querying some data from a database, writing data to a file, fetching information from the internet, all processes where your thread can do nothing but wait.

The whole idea of async-await is to let the thread do something else instead of waiting idly. For instance, the thread can go up the call stack, to see if one of the callers is not waiting.

Later, when the awaited process is finished, the thread (or a different one) continues processing the statements after the await.

So this is why you decided to use async-await: if your procedure has to wait for another process to finish, your thread can do other thing, either in your procedure, or execute statements in the procedure of your caller

The structure is similar to (sorry, my basic is a bit rusty, I'll do it in C#, but you get the gist)

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

If the awaited process in DoSomethingAsync is not finished when I start awaiting, the thread goes up my call stack to execute the statements after the call until it sees an await. Up the call stack again to see if there is someone who is not awaiting, etc.

In your program we see this pattern when you call awaitable procedures without awaiting them to finish:

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

Because GetParseExpression is async, we know that somewhere inside it has an await in it. In fact, your compiler will warn you if you forget to await in an async function.

As soon as GetParseExpression is awaiting, your procedure continues:

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

Until we are awaiting again. Continue with:

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

Until now we have not awaited yet. The results of the tasks may not be available yet. At this moment you decide that you need the results of these three functions.

Now comes the important change: In an async function don't use Task.WhaitAll, use Task.WhenAll

Task.WhenAll is an awaitable function. If you start awaiting for it, the thread goes up the call stack to see if the caller has something to do, just like it does with any awaitable function.

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

(please translate this into VB)

After all three tasks are completed, you can use property Result to access the awaited return values of the tasks.



来源:https://stackoverflow.com/questions/53157412/async-await-wait-for-all-the-results-and-continue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!