Введение

Ваша корзина для белья полна, так что вы берете ее и идете открывать стиральную машину, чтобы положить все в нее. Пока вы это делаете, вы начинаете проголодаться, может быть, пришло время готовить ужин? Давайте сначала запустим стиральную машину, смотрим на нее час, пока она не закончит, а потом идем готовить ужин. Чего ждать? Да, так обычно работает Python… (синхронно).

Не так ли это неэффективно в данном случае? Разве мы не можем просто включить стиральную машину и пойти готовить ужин, пока она продолжает работать?

Предположим следующее:
функция do_laundry() нажимает кнопку запуска на стиральной машине и ждет 10 секунд
функция cook_dinner() бросает макароны в горячую воду и оставляет ее на 10 секунд

Нормальная реализация Python

Таким образом, функция do_laundry будет выполняться в течение 10 секунд, и функция cook_dinner также будет выполняться в течение 10 секунд. Но поскольку Python запускает наш код сверху вниз, do_laundry должна завершить выполнение до того, как запустится cook_dinner. Это приведет к времени выполнения 10+10=20 секунд:

На самом деле это пустая трата времени. Разве это не должно занять 10 секунд, чтобы сделать и то, и другое? Мы можем просто приготовить ужин, пока работает стиральная машина. Как мы можем реализовать это в Python?

Асинхронная реализация

Давайте теперь воспользуемся библиотекой asyncio, которая позволит нам значительно сократить время выполнения.

Это выполняется за 10 секунд, что на 50% быстрее!

Представьте, что у нас было 5 задач вместо 2, и каждая из них выполнялась по 10 секунд. Синхронная версия займет 50 секунд, тогда как асинхронная версия займет всего 10 секунд.

Как все это работает? Обе функции работают одновременно? Ну нет… Даже если кажется, что они работают одновременно, только один из них может быть запущен в любой момент времени при использовании asyncio.

Смысл кода AsyncIO

Давайте начнем с базовой терминологии:
Корутина – функция, которая может приостановить выполнение перед возвратом.
await –> приостановит выполнение функции. пока заданная функция не завершит выполнение.
asyncio.gather -› Сопрограммы для планирования в цикле обработки событий
Привязка ввода-вывода -› ожидание ввода /выходные операции, которые необходимо выполнить

Поэтому, когда мы говорим async def func(), мы создаем сопрограмму. Это означает, что пока функция выполняется, ее можно приостановить, чтобы запустить другую функцию. И его можно приостановить с помощью await.

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

Основная тема

Основной поток — это поток по умолчанию в процессе Python.

Когда вы запускаете свою программу на Python, этот основной поток берет все эти сопрограммы (асинхронные функции) и передает их в очередь задач, которая контролируется циклом событий. .

Однопоточный цикл событий

Сопрограммы передаются в очередь задач главным потоком , где цикл событий запускает сопрограмму до тех пор, пока она не будет заблокирована в ожидании ввода-вывода ( например, ответ от пользователя).

В этом случае цикл обработки событий приостанавливает выполнение сопрограммы и передает ее операционной системе (ОС). ОС уведомляет цикл событий, когда эта задача завершает задачу ввода-вывода. Затем цикл событий может возобновить выполнение задачи.

Между передачей задачи ОС и ожиданием уведомления ОС о завершении ввода-вывода цикл обработки событий выполнит еще одну сопрограмму из очереди задач.

Выполнение программы

Таким образом, в нашем случае сопрограмма do_laundry будет запускаться циклом обработки событий, а затем, когда мы вызовем sleep_for_ten(), она будет передана операционной системе до тех пор, пока она не завершит сон. Тем временем будет запущена функция cook_dinner(), ожидающая в очереди задач. Затем, когда он вызывает sleep_for_ten(), он также будет передан операционной системе до тех пор, пока он не перейдет в спящий режим.

Через десять секунд операционная система уведомляет цикл обработки событий о том, что обе задачи перешли в спящий режим. do_laundry() теперь возобновляется и завершает выполнение, и то же самое происходит с cook_dinner(). Вот как мы смогли добиться этого за 10 секунд.

Варианты использования AsyncIO

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