Обычно, если ваша процедура вызывает другую процедуру, она должна ждать, пока эта другая процедура не будет завершена.
Иногда глубоко внутри процедуры, которую вы вызвали, поток должен бездействовать, пока другой процесс не завершится. Примерами являются запросы некоторых данных из базы данных, запись данных в файл, извлечение информации из Интернета, все процессы, в которых ваш поток может только ждать.
Вся идея 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
для доступа к ожидаемым возвращаемым значениям задач.