ensure_future
vs create_task
ensure_future
- метод создания Task
из coroutine
. Он создает задачи по-разному на основе аргумента (включая использование create_task
для сопрограмм и объектов, подобных будущим).
create_task
является абстрактным методом AbstractEventLoop
. Различные циклы событий могут реализовать эту функцию по-разному.
Вы должны использовать ensure_future
для создания задач. Вам понадобится create_task
, только если вы собираетесь реализовать свой собственный тип цикла событий.
Обновление:
@ bj0 указал на Ответ Guido на эту тему:
Точка
ensure_future()
заключается в том, что у вас есть что-то, что может быть либо сопрограммой илиFuture
(последняя включает в себяTask
, потому что это подклассFuture
), и вы хотите иметь возможность вызывать на нем метод, который определен только наFuture
(вероятно, единственным полезным примером являетсяcancel()
). Когда это ужеFuture
(илиTask
), это ничего не делает; когда он является сопрограммой, он обертывает его вTask
.Если вы знаете, что у вас есть сопрограмма и вы хотите, чтобы она была запланирована, правильный API для использования
blockquote>create_task()
. Единственный момент, когда вы должны называтьensure_future()
, - это когда вы предоставляете API (например, большинство API-интерфейсов asyncio), который принимает либо сопрограммы, либоFuture
, и вам нужно что-то сделать, чтобы потребовалосьFuture
.и позже:
В конце я все еще верю, что
blockquote>ensure_future()
является соответственно неясным именем редко требуемой части функциональность. При создании задачи из сопрограммы вы должны использовать имя с именемloop.create_task()
. Может быть, для этого должен быть псевдонимasyncio.create_task()
?Удивительно для меня. Моей главной мотивацией использовать
ensure_future
все время было то, что это функция более высокого уровня по сравнению с членом циклаcreate_task
(обсуждение содержит некоторые идеи, такие как добавлениеasyncio.spawn
илиasyncio.create_task
).Я также могу указать, что, на мой взгляд, довольно удобно использовать универсальную функцию, которая может обрабатывать любые
Awaitable
, а не сопрограммы.Однако ответ Гвидо ясен: «При создании задачи из сопрограммы вы должны использовать назначенное имя
loop.create_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') # Now you want to start long_operation, but you don't want to wait it finised: # long_operation should be started, but second msg should be printed immediately. # Create task to do so: task = asyncio.ensure_future(long_operation()) await msg('second') # Now, when you want, you can await task finised: 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()
ensure_future()
create_task
, объект цикла Как вы видите, более конкретная функция create_task.
async
функция без create_task или secure_future Простой вызов async
возвращает coroutine
>>> async def doit(i):
... await asyncio.sleep(3)
... return i
>>> doit(4)
<coroutine object doit at 0x7f91e8e80ba0>
И поскольку gather
под капотом гарантирует (ensure_future
), что args являются фьючерсами, явно ensure_future
является избыточным.
Аналогичный вопрос В чем разница между loop.create_task, asyncio.async / secure_future и Task?
для вашего примера, все три типа выполняются асинхронно. единственное отличие состоит в том, что в третьем примере вы предварительно сгенерировали все 10 сопрограмм и отправили в цикл вместе. поэтому только последний дает выход случайным образом.