Актуальная информация:
Начиная с Python 3.7 для этого была добавленаasyncio.create_task(coro)
высокоуровневая функция .
Вы должны использовать его вместо других способов создания задач из сопрограмм. Однако, если вам нужно создать задачу из произвольного объекта ожидания, вы должны использовать asyncio.ensure_future(obj)
.
Старая информация:
ensure_future
против create_task
ensure_future
это метод создания Task
из coroutine
. Он создает задачи по-разному на основе аргументов (в том числе с использованием create_task
сопрограмм и будущих объектов).
create_task
это абстрактный метод AbstractEventLoop
. Различные циклы событий могут реализовать эту функцию по-разному.
Вы должны использовать ensure_future
для создания задач. Вам понадобится create_task
только в том случае, если вы собираетесь реализовать собственный тип цикла событий.
Upd:
@ bj0 указал на ответ Гвидо по этой теме:
Дело в ensure_future()
том, что если у вас есть что-то, что может быть либо сопрограммой, либо Future
(последний включает в себя, Task
потому что это подкласс Future
), и вы хотите иметь возможность вызывать на нем метод, который определен только Future
(вероятно, о единственном полезный пример существа cancel()
). Когда это уже Future
(или Task
), это ничего не делает; когда это сопрограмма, она оборачивается в Task
.
Если вы знаете, что у вас есть сопрограмма, и вы хотите, чтобы она была запланирована, правильный API для использования - create_task()
. Единственный раз, когда вы должны звонить, ensure_future()
- это когда вы предоставляете API (например, большинство собственных API asyncio), который принимает либо сопрограмму, либо a, Future
и вам нужно что-то сделать с ним, что требует наличия Future
.
и позже:
В конце концов, я все еще считаю, что ensure_future()
это достаточно неясное название для редко необходимой части функциональности. При создании задачи из сопрограммы вы должны использовать файл с соответствующим именем
loop.create_task()
. Может быть, для этого должен быть псевдоним
asyncio.create_task()
?
Для меня это удивительно. Моей основной мотивацией для использования ensure_future
всегда было то, что это функция более высокого уровня по сравнению с членом цикла create_task
(обсуждение содержит некоторые идеи, такие как добавление asyncio.spawn
или asyncio.create_task
).
Также могу отметить, что, на мой взгляд, довольно удобно использовать универсальную функцию, которая может обрабатывать любые, Awaitable
а не только сопрограммы.
Однако ответ Гвидо ясен: «При создании задачи из сопрограммы вы должны использовать соответствующий названный loop.create_task()
»
Когда сопрограммы следует заключать в задачи?
Обернуть сопрограмму в 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 finished')
async def main():
await msg('first')
task = asyncio.ensure_future(long_operation())
await msg('second')
await task
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Выход:
first
long_operation started
second
long_operation finished
Вы можете заменить asyncio.ensure_future(long_operation())
на, await long_operation()
чтобы почувствовать разницу.
create_task
если вам действительно нужен объект задачи, который обычно вам не нужен: github.com/python/asyncio/issues/477#issuecomment-268709555