Мастер времени: как управлять задачами в asyncio с помощью call_soon и call_later

Мастер времени: как управлять задачами в asyncio с помощью call_soon и call_later


Мастер времени: как управлять задачами в asyncio с помощью call_soon и call_later

Привет, друг! Если ты когда-либо пытался одновременно варить кофе, гладить кота и отвечать на сообщения в чате — поздравляю, ты уже сталкивался с необходимостью асинхронного планирования задач! Сегодня мы разберём, как стать виртуозом управления временем в Python при помощи двух волшебных инструментов: call_soon и call_later из модуля asyncio.

Кратко о главном: цикл событий — это ваш личный дирижёр

Представьте, что ваш код — это оркестр. Без дирижёра (цикла событий) скрипки будут спорить с барабанами, а трубы перекрикивать друг друга. Asyncio аккуратно разводит их по партиям, говоря: “Сейчас ты, потом ты, а ты пока подожди, но не засыпай!“.

import asyncio

async def main():
    loop = asyncio.get_event_loop()
    # Здесь мы будем творить магию!
    
asyncio.run(main())

call_soon: “Сделай это сейчас, но дай мне закончить чай!”

Теория с примерами из жизни

loop.call_soon() — это как попросить друга: “Эй, передай соль, но только после того, как дочитаешь этот мем”. Задача ставится в очередь и выполнится сразу, как цикл событий закончит текущее дело.

Пример из кулинарии: Вы — повар, который:

  1. Ставит воду кипятиться (call_soon).
  2. Нарезает овощи (текущая задача).
  3. Как только вода закипит (срабатывает колбэк), бросает пасту.
def add_pasta():
    print("🍝 Паста отправилась в танец кипятка!")

async def cook():
    loop = asyncio.get_event_loop()
    print("🔥 Ставим воду на огонь")
    loop.call_soon(add_pasta)  # Не блокируем нарезку овощей!
    await asyncio.sleep(1)     # Имитируем нарезку
    print("🥕 Овощи готовы к салату!")

asyncio.run(cook())

Вывод:

🔥 Ставим воду на огонь
🍝 Паста отправилась в танец кипятка!
🥕 Овощи готовы к салату!

А вот и шутка:
Почему call_soon не используют в ресторанах быстрого питания?
Потому что он сразу кричит “Заказ готов!”, даже если клиент ещё не успел сесть!

call_later: “Напомни мне через 5 минут… если не забудешь”

Теория с щепоткой юмора

loop.call_later(5, callback) — это цифровой аналог фразы “Я точно начну бегать… с понедельника”. Задача выполнится через N секунд, но цикл событий продолжит работать без простоев.

Пример из жизни:
Вы ставите пирог в духовку и:

  1. Устанавливаете таймер на 30 минут (call_later).
  2. Смотрите сериал (текущая задача).
  3. По сигналу таймера (колбэк) проверяете пирог.
def check_pie():
    print("🎂 Время спасать пирог от пригорания!")

async def bake():
    loop = asyncio.get_event_loop()
    print("🔥 Пирог в духовке! Таймер на 3 секунды...")
    loop.call_later(3, check_pie)  # Через 3 секунды сработает
    await asyncio.sleep(5)         # Сериал "Кремниевая долина"
    print("📺 Серия закончилась. Что с пирогом?")

asyncio.run(bake())

Вывод:

🔥 Пирог в духовке! Таймер на 3 секунды...
🎂 Время спасать пирог от пригорания!
📺 Серия закончилась. Что с пирогом?

Шутка в тему:
call_later — любимый инструмент котов.
”Напомни хозяину дать мне корм через час…
(через час)
МЯУ! Ты это заслужил!”

Бонус: Как отменить напоминание о совещании

Каждый Handle (объект, возвращаемый call_soon/call_later) можно отменить, как неловкое сообщение в Telegram.

async def cancel_demo():
    loop = asyncio.get_event_loop()
    
    def remind():
        print("Напоминание: пора на совещание!")

    print("⏰ Установлено напоминание на через 2 секунды")
    handle = loop.call_later(2, remind)
    
    await asyncio.sleep(1)
    print("😱 Вспомнил, что совещание перенесли!")
    handle.cancel()  # Фух, пронесло!
    
    await asyncio.sleep(2)
    print("🎉 Никаких совещаний!")

asyncio.run(cancel_demo())

Реальный пример: веб-сервер с логированием

Представьте сервер, который:

  • Сразу отвечает клиенту (call_soon)
  • Через 5 секунд пишет в лог (call_later)
def log_request():
    print("📝 Лог: пользователь X получил данные")

async def handle_request():
    loop = asyncio.get_event_loop()
    print("🖥 Отправляем ответ клиенту...")
    loop.call_soon(lambda: print("⚡ Данные отправлены!"))
    loop.call_later(5, log_request)
    
asyncio.run(handle_request())

Заключение: вы теперь хрономастер!

  • call_soon — “сделай, когда освободишься, но не откладывай”.
  • call_later — “напомни мне, если не увлечёшься мемами”.

Как говаривал древний философ:
“Хороший разработчик не тот, кто успевает всё, а тот, чей event loop не падает с ошибкой ‘Task was destroyed but it is pending!’”.

Теперь вы можете смело планировать задачи, как шеф-повар на кухне стартапа — одновременно, эффективно, и с возможностью отменить подгорающий тост. Удачи в асинхронных подвигах! 🚀