Async Await Ждите всех результатов и продолжайте - PullRequest
0 голосов
/ 05 ноября 2018

Я немного запутался в том, как реализовать подход с асинхронным ожиданием и дождаться результатов, прежде чем продолжить.

Я хочу сделать 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 голосов
/ 06 ноября 2018

Обычно, если ваша процедура вызывает другую процедуру, она должна ждать, пока эта другая процедура не будет завершена.

Иногда глубоко внутри процедуры, которую вы вызвали, поток должен бездействовать, пока другой процесс не завершится. Примерами являются запросы некоторых данных из базы данных, запись данных в файл, извлечение информации из Интернета, все процессы, в которых ваш поток может только ждать.

Вся идея 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 для доступа к ожидаемым возвращаемым значениям задач.

0 голосов
/ 05 ноября 2018

Я думаю, проблема в том, что вы не запускаете реальные задачи.
Попробуйте применить пример из MDSN здесь .

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