问题
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