Актуальная информация:
Начиная с 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-268709555ensure_future
автоматически добавляет созданныйTask
в основной цикл событий?loop
аргумент ключевого слова ( см. Подпись sure_future ).await
вmsg()
вернуть управление цикл событий на второй вызов. Цикл событий после получения управления сможет запуститьсяlong_operation()
. Это сделано для демонстрации того, какensure_future
запускать сопрограмму одновременно с текущим потоком выполнения.create_task()
ensure_future()
create_task
,Как видите, create_task более конкретен.
async
функция без create_task или sure_futureПростая
async
функция вызова возвращает сопрограмму>>> async def doit(i): ... await asyncio.sleep(3) ... return i >>> doit(4) <coroutine object doit at 0x7f91e8e80ba0>
А поскольку
gather
внутренняя часть гарантирует (ensure_future
), что аргументы являются фьючерсами, явноensure_future
избыточно.Аналогичный вопрос В чем разница между loop.create_task, asyncio.async / sure_future и Task?
источник
Из официальных документов:
Деталь:
Итак, теперь, в Python 3.7 и новее, есть 2 функции-оболочки верхнего уровня (похожие, но разные):
asyncio.create_task
: которые просто вызываютevent_loop.create_task(coro)
напрямую. ( см. исходный код )ensure_future
которые также вызываются,event_loop.create_task(coro)
если это сопрограмма, или просто для обеспечения того, чтобы возвращаемый тип был asyncio.Future . ( см. исходный код ). Во всяком случае,Task
это все ещеFuture
из-за наследования класса ( ref ).Что ж, в конечном итоге обе эти функции-оболочки помогут вам вызвать
BaseEventLoop.create_task
. Единственная разница -ensure_future
принять любойawaitable
объект и помочь вам преобразовать его в будущее. А также вы можете указать свой собственныйevent_loop
параметр вensure_future
. И в зависимости от того, нужны ли вам эти возможности или нет, вы можете просто выбрать, какую оболочку использовать.источник
для вашего примера все три типа выполняются асинхронно. Единственное отличие состоит в том, что в третьем примере вы предварительно сгенерировали все 10 сопрограмм и отправили их в цикл вместе. поэтому только последний выводит случайным образом.
источник