ввода-вывода.обеспечьте будущее против 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_future
vscreate_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
. И в зависимости от того, нужны ли вам эти возможности или нет, вы можете просто выбрать, какую обертку использовать.