Información real:
A partir de Python 3.7 asyncio.create_task(coro)
, se agregó la función de alto nivel para este propósito.
Debería utilizarlo en lugar de otras formas de crear tareas a partir de tiempos de ejecución. Sin embargo, si necesita crear una tarea a partir de espera arbitraria, debe usar asyncio.ensure_future(obj)
.
Información antigua:
ensure_future
vs create_task
ensure_future
es un método para crear Task
de coroutine
. Crea tareas de diferentes maneras basadas en argumentos (incluido el uso de create_task
para corrutinas y objetos de tipo futuro).
create_task
es un método abstracto de AbstractEventLoop
. Diferentes bucles de eventos pueden implementar esta función de diferentes maneras.
Debería utilizarlo ensure_future
para crear tareas. Solo lo necesitará create_task
si va a implementar su propio tipo de bucle de eventos.
Upd:
@ bj0 señaló la respuesta de Guido sobre este tema:
El punto ensure_future()
es si tiene algo que podría ser una corrutina o un Future
(este último incluye un Task
porque es una subclase de Future
), y desea poder llamar a un método en él que solo está definido en Future
(probablemente el único siendo un ejemplo útil cancel()
). Cuando ya es un Future
(o Task
) esto no hace nada; cuando es una corrutina, lo envuelve en a Task
.
Si sabe que tiene una corrutina y desea que se programe, la API correcta que debe usar es create_task()
. El único momento en el que debería llamar ensure_future()
es cuando está proporcionando una API (como la mayoría de las API propias de asyncio) que acepta una corrutina o una Future
y necesita hacer algo que requiera que tenga una Future
.
y después:
Al final, sigo creyendo que ensure_future()
es un nombre apropiadamente oscuro para una pieza de funcionalidad que rara vez se necesita. Al crear una tarea a partir de una corrutina, debe utilizar el nombre apropiado
loop.create_task()
. ¿Quizás debería haber un alias para eso
asyncio.create_task()
?
Me sorprende. Mi principal motivación para usar ensure_future
todo el tiempo fue que es una función de nivel superior en comparación con el miembro del bucle create_task
(la discusión contiene algunas ideas como agregar asyncio.spawn
o asyncio.create_task
).
También puedo señalar que, en mi opinión, es bastante conveniente usar la función universal que puede manejar cualquiera en Awaitable
lugar de solo corrutinas.
Sin embargo, la respuesta de Guido es clara: "Al crear una tarea a partir de una corrutina, debe utilizar el nombre apropiado loop.create_task()
"
¿Cuándo se deben incluir las corrutinas en tareas?
Envolver la corrutina en una tarea: es una forma de iniciar esta corrutina "en segundo plano". He aquí un ejemplo:
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())
Salida:
first
long_operation started
second
long_operation finished
Puede reemplazarlo asyncio.ensure_future(long_operation())
con solo await long_operation()
sentir la diferencia.
create_task
si realmente necesita un objeto de tarea, que normalmente no debería necesitar: github.com/python/asyncio/issues/477#issuecomment-268709555