### Под капотом asyncio: принципы работы и ключевые концепции ### **Библиотека asyncio предоставляет полный набор инструментов для организации параллельного выполнения кода в Python с использованием концепции асинхронности. Но как на самом деле работает asyncio? Давайте разберемся в ключевых принципах и понятиях. Библиотека asyncio предоставляет полный набор инструментов для организации параллельного выполнения кода в Python с использованием концепции асинхронности. Но как на самом деле работает asyncio? Давайте разберемся в ключевых принципах и понятиях. Этот материал взят из нашей субботней [email-рассылки](https://proglib.io/w/edaee37b), посвященной Python. Подпишитесь, чтобы быть в числе первых, кто получит дайджест. **Asyncio** – библиотека, которая предоставляет инфраструктуру для написания параллельного кода с использованием концепции асинхронного программирования. Она позволяет эффективно обрабатывать многочисленные задачи ввода-вывода (например, сетевые операции или чтение/запись из файлов) без необходимости создавать множество потоков или процессов. Ключевые концепции asyncio: **Событийный цикл (Event Loop)** - Это ядро **asyncio**, которое отвечает за планирование и выполнение задач (корутин). - Реализован на языке **C** для максимальной эффективности. - Работает по принципу **однопоточной многозадачности** (single-threaded concurrency). - Постоянно опрашивает очередь событий и выполняет соответствующие задачи. **Корутины (Coroutines)** - Это специальные функции, выполнение которых можно приостанавливать на определенных точках с помощью ключевого слова `await`. - Используются для написания асинхронного, событийно-ориентированного кода. - Могут ждать асинхронные события (ввод-вывод, сигналы или другие корутины). - Определяются с помощью `async def`. **Задачи (Tasks)** - Представляют собой обертки над корутинами для их планирования и выполнения. - Создаются с помощью `asyncio.create_task(coroutine)` или `asyncio.ensure_future(coroutine)`. - Задачи можно отменять, объединять с другими задачами и отслеживать на предмет исключений. - Задачи добавляются в событийный цикл и выполняются в порядке их готовности. **Будущие объекты (Futures)** - Представляют результат асинхронной операции, который может быть доступен позже. - Задачи наследуются от класса `Future` и добавляют собственные методы управления. - Могут быть использованы для координации между разными частями программы. **Транспорты и протоколы** - **Транспорты** (sockets) отвечают за **передачу** данных по сети. - **Протоколы** определяют, как **интерпретировать** эти данные (HTTP, WebSocket и др.). - asyncio предоставляет высокоуровневые абстракции для работы с транспортами и протоколами. **Другие инструменты** - Пулы для управления ограниченными ресурсами (потоки, подпроцессы). - Синхронизаторы для координации между корутинами (**Lock****,** **Event**, **Condition)**. - Очереди для безопасной передачи данных между корутинами. - Сигналы для обработки внешних событий (UNIX-сигналы). **Вот как работает asyncio:** - Создается **событийный цикл**, который будет управлять выполнением задач. - Определяются корутины, которые выполняют некоторую работу и могут приостанавливаться на операциях ввода-вывода с помощью ключевого слова `await`. - Корутины оборачиваются в задачи с помощью функции `asyncio.create_task()`. - Задачи планируются для выполнения в событийном цикле с помощью функции `asyncio.run()` или добавляются в цикл вручную. - Событийный цикл начинает выполнять задачи по очереди. Когда задача достигает операции ввода-вывода (например, `await asyncio.sleep()`), она приостанавливается, и событийный цикл переключается на другую задачу. - Когда операция ввода-вывода завершается, задача возобновляется и продолжает выполнение до следующей операции ввода-вывода или завершения.  Статья по теме [Упрощаем разработку: асинхронные функции Python](https://proglib.io/p/uproshchaem-razrabotku-asinhronnye-funkcii-python-2019-10-06) Так asyncio позволяет эффективно использовать **один** поток для выполнения **множества** задач с операциями ввода-вывода, избегая блокировки и простоев из-за ожидания завершения этих операций. Важно отметить, что asyncio оптимален **именно для I/O-bound задач** (сеть, файловые операции и т. д.), и **не подходит для CPU-bound операций** (вычислительно-интенсивных задач), поскольку в этом случае он не сможет переключаться на другие задачи во время блокировки. Для такого рода задач лучше использовать многопоточность или многопроцессорность. Подробнее о принципах работы asyncio – в [этой статье](https://jacobpadilla.com/articles/recreating-asyncio) и [в этом видео](https://www.youtube.com/watch?v=RIVcqT2OGPA)[](http://savefrom.net/?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DRIVcqT2OGPA&utm_source=userjs-safari&utm_medium=extensions&utm_campaign=link_modifier "Получи прямую ссылку"). ======================================= 🚀 **asyncio** – это библиотека для асинхронного программирования, позволяющая писать код, выполняющий несколько задач параллельно (без потоков и процессов). ✅ async def – объявление асинхронной функции (корутина). ✅ await – приостанавливает выполнение до завершения асинхронной операции. ✅ asyncio.run() – запускает главную асинхронную функцию. ✅ asyncio.create_task() – запускает корутину в фоновом режиме. ✅ asyncio.sleep() – имитирует задержку без блокировки других задач. ```python import asyncio async def say_hello():     await asyncio.sleep(1)  # Имитация задержки     print("Привет, мир!") async def main():     task1 = asyncio.create_task(say_hello())     task2 = asyncio.create_task(say_hello())     await task1     await task2 asyncio.run(main())  # Запуск асинхронной программы ``` **Выведет с задержкой 1 секунду:** Привет, мир! Привет, мир! Обе задачи выполняются **параллельно**, а не последовательно! 📌 Когда использовать asyncio? ✅ Запросы в интернет (aiohttp). ✅ Работа с базами данных (aiomysql, asyncpg). ✅ Асинхронное чтение файлов/сокетов. ✅ Многозадачность без потоков и процессов. #====================================== **Вот как работает asyncio — без магии:** 📌 1. **Event Loop — это «планировщик», который гоняет корутины. Он сам не создаёт потоки. Он ждёт, когда одна задача «освободит» CPU, и сразу берётся за другую.** ```python import asyncio async def main():     print("Start")     await asyncio.sleep(1)     print("End") asyncio.run(main()) ``` Здесь await asyncio.sleep(1) — не блокирует поток. Это ***yield*,** который говорит: "я пока жду, можешь заняться чем-то ещё". 📌 2. **Ты не должен использовать time.sleep() в async-коде. Это блокирует весь event loop. Заменяй на await asyncio.sleep().** 📌 3. **Любая синхронная тяжёлая операция — угроза. Например, чтение файла или SQL-запрос через обычный драйвер.** ✔️ Как решить: 👍 Используй aiofiles для файлов. 👍 Используй async-драйверы (asyncpg, aiomysql, httpx и т.д.) 👍 Если нет async-аналога — выноси в ThreadPoolExecutor. ```python from concurrent.futures import ThreadPoolExecutor import asyncio def blocking():     ... async def main():     loop = asyncio.get_running_loop()     await loop.run_in_executor(None, blocking) ``` 📌 4.**Не забывай про семафоры, если запускаешь 1000 задач одновременно. async не значит всё сразу.** ```python sem = asyncio.Semaphore(100) async def safe_task():     async with sem:         await do_something() ``` 🧠 asyncio — это не про параллельность. Это про эффективное переключение задач, которые  ждут  чего-то: ответа сервера, данных, паузы. 🗣 **Применяется в: Web-серверах (FastAPI, aiohttp), парсинге, бэкенде с I/O, высоконагруженных API.**