Event Loop

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

6.1 Получение цикла событий

Цикл событий (Event Loop) является центральным компонентом в асинхронном программировании с использованием модуля asyncio в Python. Он управляет выполнением асинхронных задач, обработкой событий и выполнением операций ввода-вывода. Цикл событий позволяет нескольким задачам выполняться одновременно, не блокируя основной поток выполнения.

Создание и получение цикла событий

  • asyncio.get_event_loop(): Возвращает текущий цикл событий или создаёт новый, если текущего нет.
  • asyncio.new_event_loop(): Создаёт новый цикл событий.
  • asyncio.set_event_loop(loop): Устанавливает указанный цикл событий как текущий.

Пример:

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


import asyncio

loop = asyncio.get_event_loop()
print(loop)  # Текущий цикл событий
new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)
print(asyncio.get_event_loop())  # Новый установленный цикл событий

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

Запуск цикла событий

  • run_forever(): Запускает цикл событий и продолжает его выполнение до вызова stop().
  • run_until_complete(future): Запускает цикл событий и завершает его после завершения заданной корутины или будущего объекта.

Пример:

Цикл событий можно запустить в двух режимах: работать бесконечно — что-то типа while True, или пока не выполнится конкретная задача.


import asyncio

async def hello():
    print("Hello")
    await asyncio.sleep(1)
    print("World")
            
loop = asyncio.get_event_loop()
loop.run_until_complete(hello())
loop.close()

Если вы запустили Event Loop в режиме run_forever(), он будет крутить внутри себя цикл бесконечно. Метод run_forever() окончит работу только если какая-то асинхронная задача вызовет у нашего Event Loop метод stop().

Остановка цикла событий

  • stop(): Останавливает цикл событий.
  • is_running(): Возвращает True, если цикл событий запущен.

Пример:

Если цикл запущен в бесконечном режиме, он постоянно получает задачи и выполняет их, то сам он не остановится. Кто-то должен получить объект нашего текущего цикла и вызвать у него метод stop(). Чтобы узнать, крутится вечный цикл или нет, нужно вызвать метод is_running().


import asyncio
            
loop = asyncio.get_event_loop()
loop.stop()
print(loop.is_running())  # False

6.2 Важные методы цикла событий

Метод call_soon(callback, *args)

Планирует вызов функции callback с аргументами *args как можно скорее.


import asyncio

def my_callback():
    print("Callback executed")
            
loop = asyncio.get_event_loop()
loop.call_soon(my_callback)
loop.run_forever()

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

Метод call_later(delay, callback, *args)

Планирует вызов функции callback с аргументами *args через delay секунд.


import asyncio

def my_callback():
    print("Callback executed after delay")
            
loop = asyncio.get_event_loop()
loop.call_later(2, my_callback)
loop.run_forever()

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

Метод call_at(when, callback, *args)

Планирует вызов функции callback с аргументами *args в момент времени when.


import asyncio
import time
            
def my_callback():
    print("Callback executed at specific time")
            
loop = asyncio.get_event_loop()
when = loop.time() + 2  # Через 2 секунды от текущего времени цикла событий
loop.call_at(when, my_callback)
loop.run_forever()

Если вы хотите запустить задачу не через 5 секунд, а, например, в 15:00 или 24:00, то вам удобнее будет воспользоваться функцией call_at(), которая работает так же, как функция call_soon(), но первым параметром в неё передаётся не длительность паузы, а время, в которое нужно вызвать заданную функцию. В метод можно передавать неасинхронные функции.

Преимущества и особенности

Асинхронное выполнение: Цикл событий позволяет выполнять множество задач параллельно, не блокируя основной поток выполнения.

Эффективное управление ресурсами: Асинхронные операции ввода-вывода выполняются без блокировки, что делает программы более эффективными.

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

6.3 Взаимодействие с задачами и будущими объектами

Цикл событий управляет выполнением задач (Tasks) и будущих объектов (Futures). Он отслеживает их состояние и обеспечивает их выполнение по мере готовности.

Пример:


import asyncio

async def main():
    await asyncio.sleep(1)
    print("Task completed")
            
loop = asyncio.get_event_loop()
task = loop.create_task(main())
loop.run_until_complete(task)

В этом примере показано, как цикл событий управляет выполнением задачи, созданной с помощью метода create_task. Методы call_soon(), call_later() и call_at() можно использовать для управления выполнением задач с разной степенью срочности, что полезно при проектировании сложных асинхронных систем.

2
Задача
Модуль 1: Python Core, 14 уровень, 5 лекция
Недоступна
Создание и получение цикла событий
Создание и получение цикла событий
2
Задача
Модуль 1: Python Core, 14 уровень, 5 лекция
Недоступна
Запуск и остановка цикла событий
Запуск и остановка цикла событий
1
Опрос
Многопоточность, 14 уровень, 5 лекция
Недоступен
Многопоточность
Многопоточность
Комментарии (6)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Slevin Уровень 64
13 июля 2025
Валидатор первого задания поломан. Как обычно Если цикл был запущен и происходит переопределение текущего цикла, то валидатор считает, что переопределение не было произведено. Но ему не важно, будет ли запущен первый эвент-луп, но если будет - то просто не будет приниматься правильное решение. Потому для правильного ответа нужно писать заведомо бессмысленный код. Валидатор второго задания просто конченый. Он не принимает правильное решение. Он принимает только "правильное"(на самом деле поломанное) решение из ответа, причем если оно соответствует буква в букву. В противном случае пишет, что нет вывода статуса цикла, который вообще-то есть, потом пишет что он находится не так - хотя он там и так далее. И, кстати, решение из ответа как раз показывает, что цикл всё еще продолжает быть активным (потому что, сюрприз-сюрприз, Метод loop.stop() не останавливает цикл мгновенно, он выставляет внутренний флаг, который приводит к выходу из run_forever() после обработки текущих событий.. Поэтому вывод результата состояния цикла должен находиться ЗА ПРЕДЕЛАМИ корутины JavaRush - наймите хотя бы одного тестера на ваш дурацкий валидатор ибо я и полагаю, не я один, никогда не будем рекомендовать этот ресурс как толковое место для обучения, пока присутствуют подобные проблемы.
Slevin Уровень 64
13 июля 2025
Если вы хотите запустить задачу не через 5 секунд, а, например, в 15:00 или 24:00, то вам удобнее будет воспользоваться функцией call_at(), которая работает так же, как функция call_soon(), но первым параметром в неё передаётся не длительность паузы, а время, в которое нужно вызвать заданную функцию. В метод можно передавать неасинхронные функции. >> Не "call_soon()", а "call_later". У "call_soon()" нет параметра задержки.
Ild Gih Уровень 31
8 июня 2025
Отвратительный валидатор. Решение от разработчиков некорректное. Пора пожаловаться в техподдержку на методологию. Либо всем плевать на то, что можно растерять клиентов и свою репутацию.
Andrey Bobrovski Уровень 1
14 февраля 2025
Написано "asyncio.get_event_loop(): Возвращает текущий цикл событий или создаёт новый, если текущего нет." но выдало ошибку /ru/javarush/python/core/level14/task09/task09.py:11: DeprecationWarning: There is no current event loop l1 = asyncio.get_event_loop() но засчитало как правильно решенную
Slevin Уровень 64
13 июля 2025
ЧатГПТ: Предупреждение DeprecationWarning: There is no current event loop возникает, потому что в новых версиях Python (начиная с 3.10 и выше) вызов asyncio.get_event_loop() без запущенного цикла событий в текущем потоке считается устаревшим. В Python 3.10+ asyncio.get_event_loop() пытается вернуть текущий запущенный цикл событий. Если в текущем потоке цикл не запущен, он больше не создаёт его автоматически, а выдаёт предупреждение. Это сделано, чтобы избежать путаницы и поощрить использование более явных методов работы с циклами. Python 3.10 был официально выпущен 4 октября 2021 года. Таким образом, информация в лекции про эту функцию - устаревшая почти на 4 года...
Bahodir Daminov Уровень 90
19 октября 2024
Zapusk i ostanovka sikl sobitiy reshil s pervogo raza