ввода-вывода.обеспечьте будущее против BaseEventLoop.создать задачу против простой сопрограммы?
Я видел несколько основных руководств Python 3.5 по asyncio, выполняющих одну и ту же операцию в разных вкусах. В этом коде:
import asyncio
async def doit(i):
print("Start %d" % i)
await asyncio.sleep(3)
print("End %d" % i)
return i
if __name__ == '__main__':
loop = asyncio.get_event_loop()
#futures = [asyncio.ensure_future(doit(i), loop=loop) for i in range(10)]
#futures = [loop.create_task(doit(i)) for i in range(10)]
futures = [doit(i) for i in range(10)]
result = loop.run_until_complete(asyncio.gather(*futures))
print(result)
все три варианта выше, что определение futures переменная достигает того же результата; единственное различие, которое я вижу, заключается в том, что с третьим вариантом выполнение не в порядке (что в большинстве случаев не имеет значения). Есть ли разница? Есть ли случаи, когда я не могу просто использовать самый простой вариант (простой список Сорокины)?
4 ответа:
ensure_futurevscreate_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-интерфейсы ввода-вывода), которые можно либо сопрограмма или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()чтобы почувствовать разницу.
create_task()
- можно сопрограммы,
- задача возвращает,
- он вызывается в контексте цикла.
ensure_future()
- принимает фьючерсы, сопрограммы, ожидаемые объекты,
- возвращает задачу (или будущее, если будущее прошло).
- если данный arg является сопрограммой, он использует
create_task,- объект цикла может быть принят.
как вы можете см. create_task более конкретно.
asyncфункция без create_task или ensure_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избыточна.аналогичный вопрос в чем разница между петлей.create_task, ввода-вывода.async/ensure_future и Задача?
в вашем примере все три типа выполняются асинхронно. единственное различие заключается в том, что в третьем примере вы предварительно сгенерировали все 10 сопрограмм и отправили в цикл вместе. так что только последний дает выход случайным образом.
Примечание: только для Python 3.7 (для Python 3.5 см. более ранний ответ).
из официальных документов:
asyncio.create_task(добавлено в Python 3.7) является предпочтительным способом для создания новых задач вместоensure_future().
деталь:
Итак, теперь, в Python 3.7 и далее, есть 2 функции оболочки верхнего уровня (похожие, но разные):
asyncio.create_task: которые просто называютevent_loop.create_task(coro)напрямую. (посмотреть исходный код)ensure_future, который также называютevent_loop.create_task(coro)если это сопрограмма, или же это просто для того, чтобы тип возврата был asyncio.Будущее. (посмотреть исходный код). Во всяком случае,TaskещеFutureиз-за его наследование классов ( ref).ну, безусловно, обе эти функции обертки помогут вам вызвать
BaseEventLoop.create_task. Единственная разница -ensure_futureпринимать какие-либоawaitableобъект и поможет вам преобразовать его в будущее. А также вы можете предоставить свой собственный наensure_future. И в зависимости от того, нужны ли вам эти возможности или нет, вы можете просто выбрать, какую обертку использовать.