Подтвердить что ты не робот

Зачем использовать Async/ждать до конца

Я хотел бы получить некоторые разъяснения относительно того, что является дополнительным преимуществом использования Await и Async до конца.

Если мое приложение вызывает await Func1() (так что здесь не блокируется интерфейс). и Func1 вызывает await Func2(), но результаты из Func2() важны для Func1 для завершения задания, то зачем мне нужно Func2() ожидать. Выполнение Func1() займет столько же времени, что и до завершения Func2. Все, что ожидание делает здесь, это добавление служебных данных StateMachine.

Я что-то упустил?

4b9b3361

Ответ 1

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

Вы должны использовать async-await, если у вас есть асинхронная операция (обычно ввод-вывод, но не обязательно), и вы не хотите тратить поток, ожидающий завершения операции. Выбор операции async вместо синхронной не ускоряет работу. Это займет столько же времени (или даже больше). Он просто позволяет этому потоку продолжить выполнение некоторой другой работы с привязкой к ЦП вместо того, чтобы тратить ресурсы.

Но для возможности await этой операции метод должен быть async, а вызывающему нужно await и т.д. и т.д.

Итак, async полностью позволяет вам сделать асинхронный вызов и освободить любые потоки. Если он не является async полностью, то какой-то поток блокируется.

Итак, это:

async Task FooAsync()
{
    await Func1();
    // do other stuff
}

async Task Func1()
{
    await Func2();
    // do other stuff
}

async Task Func2()
{
    await tcpClient.SendAsync();
    // do other stuff
}

Лучше, чем это:

void Foo()
{
    Func1();
    // do other stuff
}

void Func1()
{
    Func2().Wait();  // Synchronously blocking a thread.
    // do other stuff
}

async Task Func2()
{
    await tcpClient.SendAsync();
    // do other stuff
}

Ответ 2

Основным преимуществом является то, что ожидание асинхронного метода возвращает рабочий поток в пул, который будет использоваться в других вызовах (например, веб-запросы к вашему веб-приложению .NET MVC). Асинхронная работа выполняется в потоке завершения ввода-вывода. Когда ожидаемый метод завершается, другой рабочий поток будет собирать результаты и возобновлять выполнение. Это предотвращает исчерпание пула рабочих потоков и позволяет вашему приложению обрабатывать большую нагрузку (в зависимости от процессора, памяти и сети).

Что касается "ждать до конца", это кажется проблемой для меня. Обычно await связывается с внешним ресурсом (вызов БД, запрос HTTP и т.д.), Которые ваше приложение должно ждать. Если вы ожидаете код, который не имеет внешних зависимостей ввода-вывода, вы создаете накладные расходы, которые не нужны. Возможно, существует несколько awaits в цепочке методов async, но ожидание какого-либо кода, который сам вызывает await, но не имеет никакой другой внешней зависимости IO, не является хорошим и просто добавит служебные данные обратного вызова/компилятора.

Ответ 3

Обычно рассуждения, стоящие за async/await, идут наоборот:

По какой-то причине вы решили, что Func2 будет легче писать с помощью await. Таким образом, вы упрощаете метод, добавляя желаемый await s, то есть вам также нужно изменить подпись метода (теперь он будет включать ключевое слово async и тип возврата Task или Task<T>).

Поскольку тип возвращаемого значения изменился, вы больше не можете вызывать Func2, как вы использовали (var result = Func2();), поэтому теперь вам необходимо изменить метод вызова, Func1. Самый простой способ адаптировать Func1 - это сделать также async и await Func2().

Затем по той же причине (с измененной подписью) вам нужно будет изменить все вызовы на Func1 и так далее, пока не дойдете до какой-либо точки входа (либо обработчика событий UI, либо вашего Main метод или что-то еще).

Итак, вы не начинаете делать "внешний" метод async и следуете за "внутренними" (называемыми) методами; вы обычно делаете вещи async, идя в противоположном направлении (от "самых внутренних" методов обратно к вызывающим). Этот другой ответ называет эту идею "асинхронно до конца".

Ответ 4

"В этом асинхронном методе отсутствуют операторы" ждут "и будут выполняться синхронно", что происходит, если вы не ожидаете метода async. Чтобы использовать преимущества асинхронного метода, вы должны ждать его, превратив вызывающего в метод async, который можно ожидать и т.д. И т.д.

На блок-схеме вы видите, что метод async возвращает задание (обещание выполнить работу в будущем) и дает контроль над ним. Затем вызывающий может продолжить работу, не зависящую от этого результата. Понятно, что это нужно, чтобы выровнять стек вызовов, чтобы найти всю эту полезную работу, которая может быть выполнена без результата (в приложении UI эта работа будет включать разблокирование пользовательского интерфейса, поэтому она полностью асинхронизируется с обработчиком событий в приведенном ниже примере).


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

Я много слышал, что основная проблема с асинхронным ожиданием - это слишком простой синтаксис для того, что он на самом деле делает. Поток программы усложняется. Мне очень нравится async-wait, но, к сожалению, в большинстве асинхронных кодов я видел, что это не стоит и просто бесполезно разрушает мой стек вызовов.

Хорошо иметь в виду правило 50мс.

"Это правило, согласно которому Microsoft следует за API-интерфейсом WinRT: все, что занимает менее 50 мс, считается" быстрым "и достаточно близко к" немедленному ", что им не нужен асинхронный API.

Это используется в контексте поощрения async-ожидания. Тем не менее, я думаю, что в равной степени это должно быть применено, чтобы сказать разработчикам, использующим async-wait, для практически неотложных функций, чтобы вырезать его.


https://msdn.microsoft.com/en-us/cc300389.aspx#E

Ответ 5

В приложении async на основе пользовательского интерфейса обеспечивается очень сжатый способ обработки асинхронных вызовов, что приводит к обновлению пользовательского интерфейса. Если обработчик "верхнего уровня" из пользовательского интерфейса ожидает результата, тогда потенциальная реальная польза для всей цепочки не будет достигнута, если это имеет смысл сделать это. Цель проектирования async-ожидания заключалась в том, чтобы сделать асинхронное программирование более синхронным и непрерывным и не иметь обратных вызовов, разбросанных по и т.д., Что делает асинхронное кодирование более оцененным. Это не то, что вам нужно использовать везде произвольно.