Что отличает asyncio.ensure_future и asyncio.AbstractEventLoop.create_task? [Дубликат]

53
задан crusaderky 31 March 2016 в 20:15
поделиться

3 ответа

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 для использования create_task(). Единственный момент, когда вы должны называть ensure_future(), - это когда вы предоставляете API (например, большинство API-интерфейсов asyncio), который принимает либо сопрограммы, либо Future, и вам нужно что-то сделать, чтобы потребовалось Future.

и позже:

В конце я все еще верю, что 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(), чтобы почувствовать разницу.

72
ответ дан Will 25 August 2018 в 11:21
поделиться

create_task()

  • принимает сопрограммы,
  • возвращает задачу,
  • вызывается в контексте цикла.

ensure_future()

  • принимает фьючерсы, сопрограммы, ожидаемые объекты,
  • возвращает задачу (или будущее, если будущее прошло).
  • , если данный arg является сопроводителем, который он использует 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?

27
ответ дан Jaanus Varus 25 August 2018 в 11:21
поделиться

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

2
ответ дан ospider 25 August 2018 в 11:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: