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-268709555ensure_future
Agrega automáticamente lo creadoTask
al bucle de eventos principal?loop
argumento de palabra clave ( consulte la firma de asegurar el futuro ).await
dentromsg()
para devolver el control al bucle de eventos en la segunda llamada. El bucle de eventos una vez que reciba el control podrá comenzarlong_operation()
. Se hizo para demostrar cómoensure_future
comienza una rutina para ejecutarse simultáneamente con el flujo de ejecución actual.create_task()
ensure_future()
create_task
,Como puede ver, create_task es más específico.
async
función sin create_task o asegurar_futuroLa
async
función de invocación simple devuelve una rutinaY dado que lo
gather
oculto asegura (ensure_future
) que los argumentos son futuros, explícitamenteensure_future
es redundante.Pregunta similar ¿ Cuál es la diferencia entre loop.create_task, asyncio.async / secure_future y Task?
fuente
De los documentos oficiales:
Detalle:
Así que ahora, en Python 3.7 en adelante, hay 2 funciones contenedoras de nivel superior (similares pero diferentes):
asyncio.create_task
: que simplemente llamaevent_loop.create_task(coro)
directamente. ( ver código fuente )ensure_future
que también llamaevent_loop.create_task(coro)
si es una rutina o simplemente para asegurar que el tipo de retorno sea un asyncio.Future . ( ver código fuente ). De todos modos,Task
sigue siendoFuture
debido a su herencia de clases ( ref ).Bueno, en definitiva ambas funciones contenedoras te ayudarán a llamar
BaseEventLoop.create_task
. La única diferencia esensure_future
aceptar cualquierawaitable
objeto y ayudarte a convertirlo en un futuro. Y también puede proporcionar su propioevent_loop
parámetro enensure_future
. Y dependiendo de si necesita esa capacidad o no, simplemente puede elegir qué envoltorio usar.fuente
para su ejemplo, los tres tipos se ejecutan de forma asincrónica. la única diferencia es que, en el tercer ejemplo, generaste previamente las 10 corrutinas y las enviaste al ciclo juntas. por lo que solo el último da salida al azar.
fuente