C# async await Потоки ч.6

Приветствую всех, сегодня поговорим о продолжении темы связанной с потоками, это часть 6.  Читать Потоки ч.1  Читать Потоки ч.2 Читать Потоки ч.3 Читать потоки ч.4 Читать потоки ч.5

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

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

Оператор await заставляет метод, запускающий этот код, остановиться и дождаться завершения метода ShowAsync(), в итоге метод блокируется, пока пользователь не выберет какую-либо команду. В это время остальная программа продолжает отвечать на другие события. Как только метод ShowAsync() вернет управление, вызывавший его метод начнет работу с прерванной точки (хотя он может и дожидаться завершения возникших в промежутке событий). Метод, использующий оператор await, должен объявляться с модификатором async:

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

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

ВАЖНО! Стоит помнить что async\await в разных контекстах приложений используется по разному, к примеру в asp и wpf они имеют отличия в работе.

Простой пример работы с async await:

С первого взгляда кажется ничего сложного, и возникает больше вопросов чем ответов, если посмотреть код метода MethodAsync вообще не понятно что делает async и для чего нужен вообще await. Данный пример не несет полезной нагрузки и мы могли обойтись без этих ключевых слов, ничего бы не изменилось, однако он демонстрирует работу async await. Все дело в том что эти слова позволяют компилятору указать метод, для которого будет произведена автоматическая генерация кода. Это создано для упрощения в разработке и уменьшения кода программы, вам не придется строчить кучу однотипного кода каждый раз, это все будет сделано за вас!

А теперь посмотрите как наш пример, выглядит под рефлектором,  с генерировалось куча строк кода.

Представленный выше код, я не стал исправлять, а скопировал его как он находился в рефлекторе. Давайте его разберем для большего понимания. Наши методы не поменялись, за исключением MethodAsync() и появился класс d__1 : IAsyncStateMachine . Внутри которого имеются методы MoveNext(); и SetStateMachine(); Внутри класса так же имеются поля, основное из них это public AsyncVoidMethodBuilder t__builder; который представляет конструктор для асинхронных методов, которые не возвращают никакое значение. Метод stateMachine.t__builder.Start < Prog.d__1 > (ref stateMachine); вызывает метод MoveNext(); Где происходит запуск задачи, нового потока и вызова метода Method(); Внутри метода MoveNext() так же имеется переменная которая ожидает завершения задачи, по окончанию работы метода, условия if (num1 != 0) становиться false и метод MoveNext(); завершает свою работу. Для понимания работы я вам советую скопировать код в студию и под отладкой посмотреть его работу.

 

В следующем примере я покажу как можно передать аргументы в метод, а так же получить из него результат:

 

Когда вызывается Task. Factory, происходит обращение к статическому свойс­тву класса Task, которое возвращает стандартный объект фабрики задач, т.е. TaskFactory. Назначение фабрики задач заключается в создании задач — в частнос­ти, трех видов задач:

  • «обычных» задач (через метод StartNew);
  • продолжений с множеством предшественников (через методы ContinueWhenAllи ContinueWhenAny);
  • задач, которые являются оболочками для методов, следующих устаревшему шаб­лону АРМ

Следующий пример покажет как рассчитать сумму чисел в методе в отдельном потоке  и вернуть результат в основной поток:

 

Программисты считают, что модификатор async и оператор await вносят в код путаницу. Поэтому важно усвоить следующее. ‰

  • Если метод объявлен с модификатором async , это еще не означает, что он выполняется в асинхронном режиме. Это означает, что метод может содержать инструкции, которые могут выполняться в асинхронном режиме.‰
  • Оператор await показывает, что метод должен быть запущен в отдельной задаче и что вызывающий код приостанавливается, пока не будет завершен вызов метода. Поток, используемый вызывающим кодом, высвобождается и может быть использован повторно. Это важно в том случае, если это тот самый поток, который используется пользовательским интерфейсом, поскольку это позволяет сохранить его отзывчивость на действия пользователя.
  • Оператор await не является функциональным аналогом принадлежащего задаче метода Wait , который всегда блокирует текущий поток и не допускает его повторного использования, пока задача не завершится.‰ Изначально код, возобновляющий выполнение после оператора await , пытается получить исходный поток, который был использован для вызова асинхронного метода. Если этот поток занят, код будет блокирован. Чтобы указать, что выполнение кода может быть возобновлено в любом доступном потоке, и сократить шансы на его блокировку, можно воспользоваться методом ConfigureAwait(false) . Особую пользу это принесет веб-приложениями сервисам, которым может понадобиться обслуживать многие тысячи одновременно поступающих запросов.
  • Неосмотрительное использование асинхронных методов, возвращающих результаты и запускаемых в потоке пользовательского интерфейса, может привести к возникновению взаимных блокировок и стать причиной зависания приложения.

Продолжение следует…

 

 

 

 

 

 

 

Обновлено: 11.04.2020 — 10:21

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.