JavaRush /Курсы /Модуль 1: Python Core /Асинхронные методы

Асинхронные методы

Модуль 1: Python Core
14 уровень , 2 лекция
Открыта

3.1 Модуль asyncio

Свои потоки для асинхронных подзадач уже давно никто не создаёт. Вернее, создавать их можно, но такие действия считаются слишком низкоуровневыми и используются лишь разработчиками фреймворков. И то, когда без них совсем не обойтись.

Сейчас в моде асинхронное программирование, операторы async/await и корутины с тасками. Но обо всём по порядку…

Немного истории

Изначально в Python для решения задач асинхронного программирования использовались корутины, основанные на генераторах. Потом, в Python 3.4, появился модуль asyncio (иногда его название записывают как async IO), в котором реализованы механизмы асинхронного программирования. В Python 3.5 появилась конструкция async/await.

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

Модуль asyncio

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

Корутины (Coroutines)

Корутины — это асинхронные функции, определяемые с помощью ключевого слова async def. Корутины позволяют приостанавливать своё выполнение с помощью ключевого слова await, что позволяет другим корутинам выполняться в это время.


import asyncio

# Определение асинхронной функции (корутины)
async def main():
    print('Hello ...')
    # Приостанавливаем выполнение на 1 секунду
    await asyncio.sleep(1)
    print('... World!')

# Запуск асинхронной функции main() в цикле событий
asyncio.run(main())

Цикл событий (Event Loop)

Цикл событий управляет выполнением корутин, задач и других асинхронных операций. Вызов asyncio.run() запускает цикл событий и выполняет корутину до завершения.


import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

# Получение текущего цикла событий
loop = asyncio.get_event_loop()
# Запуск корутины до завершения
loop.run_until_complete(main())
# Закрытие цикла событий после завершения всех задач
loop.close()

Задачи (Tasks)

Задачи позволяют запускать корутины параллельно. Создаются с помощью asyncio.create_task() или asyncio.ensure_future().


import asyncio

# Определение корутины, которая будет выполнена с задержкой
async def say_after(delay, what):
    # Приостанавливаем выполнение на заданное время
    await asyncio.sleep(delay)
    print(what)

# Основная корутина
async def main():
    # Создаем задачи для параллельного выполнения корутин
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))
    
    # Ждем завершения обеих задач
    await task1
    await task2

# Запуск основной корутины
asyncio.run(main())

Фьючерсы (Futures)

Объекты Future представляют собой результаты асинхронных операций, которые будут доступны в будущем. Например, они используются для ожидания завершения асинхронной задачи.


import asyncio

# Определение корутины, которая имитирует долгую задачу
async def long_running_task():
    print('Task started')
    # Приостанавливаем выполнение на 3 секунды
    await asyncio.sleep(3)
    print('Task finished')
    return 'Result'

# Основная корутина
async def main():
    # Создаем фьючерс для ожидания завершения задачи
    future = asyncio.ensure_future(long_running_task())
    # Ждем завершения задачи и получаем результат
    result = await future  
    print(f'Task result: {result}')

# Запуск основной корутины
asyncio.run(main())

3.2 Асинхронная функция — async def

Асинхронная функция объявляется так же, как и обычная, только перед ключевым словом def нужно написать слово async.


async def ИмяФункции(параметры):
    код функции

Асинхронная функция объявляется как обычная, вызывается как обычная, но вот результат она возвращает другой. Если вызвать асинхронную функцию, то она вернёт не результат, а специальный объект — корутину.

Можно даже это проверить:


import asyncio

async def main():
    print("Hello World")
            
# Вызов асинхронной функции, который возвращает корутину
result = main()
# Проверяем тип результата
print(type(result)) # <class 'coroutine'>

Что же происходит? Когда вы помечаете функцию словом async, то фактически добавляете к ней декоратор, который делает примерно это:


def async_decorator(func):
    # Создаем объект Task
    task = Task()
    # Передаем в него нашу функцию func, чтобы он её выполнил
    task.target = func  
    # Добавляем объект task в очередь задач — Event Loop
    eventloop.add_task(task)  
    # Возвращаем объект task
    return task 

А ваш код становится похож на:


import asyncio

@async_decorator
def main():
    print("Hello World")
            
result = main()
print(type(result)) # <class 'coroutine'>

Смысл данной аналогии следующий:

Когда вы вызываете асинхронную функцию, создаётся специальный объект Task, который будет выполнять вашу функцию, но когда-то в будущем. Может через 0.0001 секунды, а может и через 10.

Этот объект task вам сразу и возвращается как результат вызова вашей асинхронной функции. Это и есть корутина. Ваша асинхронная функция, возможно, вообще ещё не начала выполняться, а объект task (корутина) у вас уже есть.

Зачем вам этот task (корутина)? Вы мало что можете с ним сделать, но возможно сделать 3 вещи:

  • Подождать, пока асинхронная функция выполнится.
  • Подождать, пока асинхронная функция закончит выполняться и получить из корутины результат выполнения функции.
  • Подождать, пока выполнится 10 (любое число) асинхронных функций.

Как это сделать, я расскажу ниже.

3.3 Оператор await

Большая часть действий с корутиной начинается с «подождать выполнения асинхронной функции». Поэтому для этого действия у нас есть специальный оператор await.

Вам нужно просто написать его перед корутиной:


await корутина

Или сразу перед вызовом асинхронной функции:


await асинхронная_функция(аргументы)

Когда Python встречает в коде оператор await, он приостанавливает выполнение текущей функции и ждёт, пока корутина не выполнится — пока не завершится асинхронная функция, на которую ссылается корутина.

Важно! Оператор await используется только внутри асинхронной функции для приостановки выполнения до тех пор, пока не завершится другая корутина или асинхронная операция.

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

Пример:


import asyncio

# Определение асинхронной функции
async def async_print(text):
    print(text)
        
# Основная асинхронная функция
async def main():
    # Используем await для ожидания выполнения асинхронной функции
    await async_print("Hello World")
        
# Запуск основного цикла событий и выполнение корутины main()
asyncio.run(main()) # запускает асинхронную функцию

На самом деле оператор await работает ещё хитрее — он также возвращает результат выполнения асинхронной функции, у которой он был вызван.

Пример:


import asyncio

# Определение асинхронной функции, которая складывает два числа
async def async_add(a, b):
    return a + b
        
# Основная асинхронная функция
async def main():
    # Используем await для получения результата выполнения async_add
    sum = await async_add(100, 200)
    print(sum)
        
# Запуск основного цикла событий и выполнение корутины main()
asyncio.run(main()) #запускает асинхронную функцию

Итак, подведём итоги, оператор await:

  • Приостанавливает текущую асинхронную функцию до тех пор, пока не завершится другая корутина или асинхронная операция.
  • Возвращает результат выполнения асинхронной операции или корутины.
  • Можно использовать только внутри асинхронной функции.
2
Задача
Модуль 1: Python Core, 14 уровень, 2 лекция
Недоступна
Создание и выполнение асинхронных функций
Создание и выполнение асинхронных функций
2
Задача
Модуль 1: Python Core, 14 уровень, 2 лекция
Недоступна
Выполнение нескольких задач параллельно
Выполнение нескольких задач параллельно
Комментарии (12)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Natalia Уровень 27
25 декабря 2025
Почему готовый ответ от JavaRush не проходит тестирование?)))) какой то сюр.
Artem Уровень 30
18 сентября 2025
Это одна из самых главных фишек на мой взгляд JavaRush, не только на этом курсе Python, она побуждает к самостоятельности, смекалке, а не просто скопировать задачу и сдать решение!!! Как многие судя по коментам возмущаются, зачем задача, которую можно тупо скопировать и валидатор примет решение, если не копировать, а напечатать, в голове отложится что то кроме пустоты, все не просто так)
Vanil'ka Уровень 25
3 сентября 2025
Короче тема мутная. Пришлось много гуглить. Составил конспект: КОНСПЕКТ Если ничего не поняли, можете почитать.
Long_byte Уровень 55
24 июля 2025
в чем суть вообще асинхронной функции что это вообще асинхронное программирование чем отличается асинхронное программирование от многопоточности
Slevin Уровень 5
12 июля 2025
Для второй задачи asyncio.gather() - описан в следующей лекции. Если кратко - закидываете в него фьючерсы или таски и получаете кортеж результатов выполнения каждого элемента.
Japan_Dragon Уровень 32
3 марта 2025
Если вдруг кто-то будет из простых смертных проходить, то вот простое объяснение что такое синхронный/ассинхронный формат обмена данными: Синхронный и асинхронный обмен данными — это два разных способа, как устройства (или программы) могут общаться друг с другом. - **Синхронный обмен** — это когда ты что-то делаешь, и система сразу отвечает. Например, ты нажал кнопку, и ждешь, пока сервер вернет ответ. Всё происходит поочередно: ты делаешь действие, и пока не получишь ответ, не можешь двигаться дальше. То есть, всё должно быть сделано в строгой последовательности. - **Асинхронный обмен** — это когда ты ничего не ждешь и делаешь другие дела, а сообщение приходит само, без твоего запроса. Например, ты сидишь в мессенджере и переписываешься, а кто-то тебе вдруг пишет сообщение, даже если ты не нажимал кнопку "получить сообщение". То есть, система работает в фоновом режиме и не заставляет тебя ждать.
Денис Уровень 33
22 января 2025
Посмотреть что хочет получить gather и догадаться что с этим делать можно непосредственно в IDE провалившись в функцию по ctrl + B
Slevin Уровень 5
12 июля 2025
Огромное спасибо за хоткей!
Артём Васенин Уровень 82
7 декабря 2024
Это уже не вызывает удивления, когда получаешь задачу по функционалу который еще не был в лекции
Андрей Уровень 15
31 октября 2024
В следующей лекции описан метод asyncio.gather() необходимый для решения второй задачи.
Slevin Уровень 5
12 июля 2025
в этом курсе - такой бред - это норма!
Семён Уровень 34
12 сентября 2024
В последней задаче нужно использовать функцию asyncio.gather, но в лекции она не упоминается, почитать можно тут: https://docs-python.ru/standart-library/modul-asyncio-python/funktsija-gather-modulja-asyncio/