Сообщить об ошибке.

Функция create_task() модуля asyncio в Python

Создание задачи для планирования выполнения сопрограммы

Синтаксис:

import asyncio

asyncio.create_task(coro, *, name=None, context=None)

Параметры:

  • coro - асинхронная функция coroutine,
  • name=None - имя задачи.
  • context=None - пользовательский contextvars.Context для запуска сопрограммы.

Возвращаемое значение:

Описание:

Функция create_task() модуля asyncio оборачивает сопрограмму coro в задачу task и планирует ее выполнение в ближайшее время. Возвращает объект Task. Объект задачи всегда следует запускать с оператором await.

Если аргумент name не равен None, то name устанавливается как имя задачи с помощью метода объекта Task.set_name().

Необязательный ключевой аргумент контекста context, позволяет указать пользовательский contextvars.Context для запуска сопрограммы. Текущая копия контекста создается, когда контекст не предоставляется.

Задача будет выполняется в цикле событий, который возвращает функция низкоуровнего API asyncio.get_running_loop(). Если в текущем потоке нет запущенного цикла событий, то возникает исключение RuntimeError.

Обратите внимание, что asyncio.TaskGroup.create_task() (добавлена в Python3.11) - это более новая альтернатива, которая позволяет удобно ожидать группу связанных задач.

Важно! Сохраняйте ссылку на результат этой функции, чтобы задача не исчезла в процессе выполнения. Цикл событий сохраняет только слабые ссылки на задачи. Задача, на которую больше нигде нет ссылок, может быть удалена сборщиком мусора в любое время, даже до того, как она будет выполнена. Для надежных фоновых задач типа "запустил и забыл" нужно собрать их в коллекцию:

# это набор запускаемых задач
background_tasks = set()

for i in range(10):
    task = asyncio.create_task(some_coro(param=i))

    # Добавление задачи в набор создает сильную ссылку.
    background_tasks.add(task)

    # Чтобы не хранить ссылки на завершенные задачи, необходимо 
    # продумать, чтобы после завершения каждая задача
    # самостоятельно удаляла свою ссылку из этого набора:
    task.add_done_callback(background_tasks.discard)

Асинхронный запуск создаваемых задач можно планировать при помощи функции asyncio.gather().

Функция asyncio.create_task() была добавлена ​​в Python 3.7. До Python 3.7, для создания задач, нужно было использовать низкоуровневую функцию asyncio.ensure_future():

Изменено в Python 3.8: добавлен аргумент name.

Изменено в версии 3.11: добавлен аргумент context.

Обратите внимание, что запускаемые сопрограммы (асинхронные функции) не должны содержать внутри себя операции, блокирующие ход выполнения программы! Другими словами, нельзя какую либо встроенную синхронную функцию (типа socket.getnameinfo()) обернуть в асинхронную функцию (async def ...) и думать, что этот код будет работать асинхронно. НЕТ. Такая сопрограмма так же будет блокировать остальной код.

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

Пример создания и запуска задачи.

В приведенном ниже примере, попробуйте заменить создание задачи create_task(long_operation()) просто на await long_operation(), чтобы почувствовать разницу. Если будете выполнять этот эксперимент, то не забудьте убрать await task.

import asyncio

async def msg(text):
    # эмитируем короткую 
    # задержку в выполнении
    await asyncio.sleep(0.1)
    print(text)

async def long_operation():
    # эмитируем долгую 
    # задержку в выполнении
    print('long_operation started')
    await asyncio.sleep(3)
    print('long_operation complete')

# основной цикл программы
async def main():
    # легкая сопрограмма
    await msg('1 msg complete')

    # Здесь запустим `long_operation()`, но ждать, пока она 
    # выполнится не хотим, т.к. необходимо получить второе 
    # сообщение как можно раньше. Для этого создаем для нее задачу... 
    task = asyncio.create_task(long_operation())
    
    # легкая сопрограмма
    await msg('2 msg complete')

    # Теперь можно дождаться завершения 
    # задачи или отменить ее
    await task

if __name__ == "__main__":
    # запускаем ВСЕ на выполнение
    asyncio.run(main())

# 1 msg complete
# long_operation started
# 2 msg complete
# long_operation complete