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

Класс Task() модуля asyncio в Python.

Управление ходом выполнения задачи.

Синтаксис:

import asyncio

task = asyncio.Task(coro, *, loop=None, name=None)

Параметры:

  • coro - сопрограмма Python,
  • loop=None - параметр цикла (устаревший с Python-3.8, будет удален в Python-3.10),
  • name=None - имя задачи.

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

Описание:

Класс Task() модуля asyncio это объект, который запускает сопрограмму Python и похож на объект asyncio.Future, т.к. является подклассом этого объекта.

Экземпляры класса asyncio.Task лучше не создавать в потоках, т. к. они НЕ потокобезопасные.

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

Циклы событий используют совместное планирование. Другими словами, цикл событий запускает одну задачу за раз. Пока объект задачи Task ожидает готовности Future, цикл событий запускает другие задачи, обратные вызовы или выполняет операции ввода-вывода.

Для создания экземпляров задач необходимо использовать высокоуровневую функцию asyncio.create_task(). Создание задач вручную не рекомендуется, но возможен с использованием низкоуровневых функций loop.create_task() или asyncio.ensure_future().

Чтобы отменить запущенную задачу, используйте метод Task.cancel(). Его вызов приведет к тому, что задача выдаст исключение asyncio.CancelledError, которое поступит в обернутую сопрограмму. Если, во время отмены, сопрограмма ожидает готовности объекта Future, то объект Future будет отменен.

Метод Task.cancelled() можно использовать для проверки того, была ли задача отменена. Метод возвращает True, если обернутая сопрограмма не подавила исключение asyncio.CancelledError и была фактически отменена.

Класс asyncio.Task() наследует от объекта asyncio.Future все его методы, кроме Future.set_result() и Future.set_exception().

Задачи Task поддерживают модуль contextvars. Когда задача создается, то она копирует текущий контекст, а затем запускает свою сопрограмму в скопированном контексте.

Изменения:

  • Новое в Python 3.7: добавлена поддержка модуля contextvars.
  • Новое в Python 3.8: добавлен параметр name.
  • Параметр цикла loop считается устаревшим с Python 3.8, будет удален в Python 3.10.

Методы объекта asyncio.Task().


Task.cancel():

Метод Task.cancel() создает запрос на отмену задания. Таким образом обеспечивает появления исключения asyncio.CancelledError, которое передается в обернутую сопрограмму на следующем шаге цикла событий.

Затем сопрограмма имеет шанс очистить или даже отклонить запрос на отмену, подавив исключение с помощью try ... finally.

try: 
... 
except CancelledError: 
... 
finally:
...

Следовательно, в отличие от Future.cancel(), Task.cancel() не гарантирует, что задача будет отменена, хотя полное подавление отмены не является распространенным явлением и активно не приветствуется.

В следующем примере показано, как сопрограммы могут перехватывать запрос отмены:

async def cancel_me():
    print('cancel_me(): перед ожиданием')
    try:
        # ждем 1 час
        await asyncio.sleep(3600)
    except asyncio.CancelledError:
        print('cancel_me(): отмена ожидания')
        # поднимаем еще раз 
        # перехваченное исключение
        raise
    finally:
        print('cancel_me(): после ожидания')

async def main():
    # Создаем задачу для "cancel_me()"
    task = asyncio.create_task(cancel_me())

    # Ждем 1 сек.
    await asyncio.sleep(1)

    # Даем запрос на отмену
    task.cancel()

    try:
        await task
    except asyncio.CancelledError:
        print("main(): `cancel_me()` теперь отменен.")

asyncio.run(main())

# Expected output:
#
#     cancel_me(): перед ожиданием
#     cancel_me(): отмена ожидания
#     cancel_me(): после ожидания
#     main(): cancel_me() теперь отменен.

Task.cancelled():

Метод Task.cancelled() возвращает True, если задача Task отменена.

Задача отменяется, когда отмена была запрошена с помощью метода Task.cancel() и обернутая сопрограмма распространила переданное в нее исключение asyncio.CancelledError.

Task.done():

Метод Task.done() возвращает True, если задача Task выполнена.

Задача считается выполненной, когда обернутая сопрограмма либо отработала и вернула результат, либо вызвала исключение, либо была отменена.

Task.result():

Метод Task.result() возвращает результат выполнения задачи Task.

  • Если задача выполнена, то возвращается результат обернутой сопрограммы.
  • Если сопрограмма вызвала исключение, то это исключение вызывается повторно.
  • Если задача была отменена, то метод Task.result() вызывает исключение asyncio.CancelledError.
  • Если результат задачи еще не доступен, то этот метод вызывает исключение asyncio.InvalidStateError.

Task.exception():

Метод Task.exception() возвращает исключение из задачи Task.

  • Если обернутая сопрограмма вызвала исключение, то возвращается это исключение.
  • Если обернутая сопрограмма вернула нормальный результат, то этот метод возвращает None.
  • Если задача была отменена, то метод Task.exception() вызывает исключение asyncio.CancelledError.
  • Если задача еще не выполнена, то метод вызывает исключение исключение asyncio.InvalidStateError.

Task.add_done_callback(callback, *, context=None):

Метод Task.add_done_callback() добавляет обратный вызов callback, который будет запускаться, когда задача будет выполнена.

Внимание! Этот метод следует использовать только в низкоуровневом коде, основанном на обратном вызове.

Смотрите документацию Future.add_done_callback() для получения более подробной информации.

Task.remove_done_callback(callback):

Метод Task.remove_done_callback() удаляет обратный вызов callback из списка обратных вызовов.

Внимание! Этот метод следует использовать только в низкоуровневом коде, основанном на обратном вызове.

Смотрите документацию Future.remove_done_callback() для более подробной информации.

Task.get_stack(*, limit=None):

Метод Task.get_stack() возвращает список кадров стека для этой задачи.

  • Если обернутая сопрограмма не завершена, то возвращается стек, в котором она приостановлена.
  • Если сопрограмма завершилась успешно или была отменена, то возвращается пустой список.
  • Если сопрограмма была прервана из-за исключения, то возвращается список кадров трассировки.

Кадры всегда отсортированы от самых старых до самых новых. Для приостановленной сопрограммы возвращается только один кадр стека.

Необязательный аргумент limit устанавливает максимальное количество возвращаемых кадров. По умолчанию возвращаются все доступные кадры.

Порядок возвращаемого списка различается в зависимости от того, возвращается ли стек или трассировка: возвращаются самые новые кадры стека, но, возвращаются самые старые кадры трассировки, что соответствует поведению модуля traceback.

Task.print_stack(*, limit=None, file=None):

Метод Task.print_stack() печатает стек или трассировку для этой задачи.

Метод дает выходные данные, аналогичные выходным данным модуля traceback для кадров, полученных с помощью метода Task.get_stack().

Аргумент limit передается напрямую в метод Task.get_stack().

Аргумент file - это поток ввода/вывода, в который записывается вывод. По умолчанию вывод записывается в sys.stderr.

Task.get_coro():

Метод Task.get_coro() возвращает объект сопрограммы, обернутую в задачу Task.

Новое в Python 3.8.

Task.get_name():

Метод Task.get_name() возвращает имя name задачи Task.

Если имя задачи Task не было явно установлено, то по умолчанию модуль asyncio генерирует name во время создания экземпляра.

Новое в Python 3.8.

Task.set_name(value):

Метод Task.set_name() устанавливает имя name задачи Task.

Аргументом значения может быть любой объект, который затем преобразуется в строку.

В реализации задачи по умолчанию имя будет отображаться в выводе repr() объекта задачи.

Новое в Python 3.8.

Task.all_tasks(loop=None):

Метод Task.all_tasks() представляет собой метод класса, который возвращает множество всех задач для текущего цикла событий.

По умолчанию возвращаются все задачи. Если аргумент loop равен None, то для получения текущего цикла используется функция asyncio.get_event_loop().

Внимание! Метод устарел с версии Python 3.7 и удален в Python 3.9: не вызывайте его как метод задачи, вместо него используйте функцию asyncio.all_tasks().

Task.current_task(loop=None):

Метод Task.current_task() представляет собой метод класса, который возвращает текущую запущенную задачу или None.

Если аргумент loop=None, то для получения текущего цикла используется функция asyncio.get_event_loop().

Внимание! Метод устарел с версии Python 3.7 и удален в Python 3.9: не вызывайте его как метод задачи, вместо него используйте функцию asyncio.current_task().


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

В приведенном ниже примере, попробуйте заменить создание задачи 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