python - loop - Asyncio.gather vs asyncio.wait
python async api (3)
asyncio.gather
y
asyncio.wait
parecen tener usos similares: tengo un montón de cosas asíncronas que quiero ejecutar / esperar (no necesariamente esperando que una termine antes de que comience la siguiente).
Usan una sintaxis diferente y difieren en algunos detalles, pero me parece muy poco pitónico tener 2 funciones que tienen una superposición tan grande en la funcionalidad.
¿Qué me estoy perdiendo?
Aunque similar en casos generales ("ejecutar y obtener resultados para muchas tareas"), cada función tiene alguna funcionalidad específica para otros casos:
asyncio.gather
Devuelve una instancia futura, lo que permite la agrupación de tareas de alto nivel:
import asyncio
from pprint import pprint
import random
async def coro(tag):
print(">", tag)
await asyncio.sleep(random.uniform(1, 3))
print("<", tag)
return tag
loop = asyncio.get_event_loop()
group1 = asyncio.gather(*[coro("group 1.{}".format(i)) for i in range(1, 6)])
group2 = asyncio.gather(*[coro("group 2.{}".format(i)) for i in range(1, 4)])
group3 = asyncio.gather(*[coro("group 3.{}".format(i)) for i in range(1, 10)])
all_groups = asyncio.gather(group1, group2, group3)
results = loop.run_until_complete(all_groups)
loop.close()
pprint(results)
Todas las tareas en un grupo pueden cancelarse llamando a
group2.cancel()
o incluso
all_groups.cancel()
.
Ver también
.gather(..., return_exceptions=True)
,
asyncio.wait
Admite la espera para detenerse después de que se realiza la primera tarea, o después de un tiempo de espera especificado, lo que permite una precisión de operaciones de menor nivel:
import asyncio
import random
async def coro(tag):
print(">", tag)
await asyncio.sleep(random.uniform(0.5, 5))
print("<", tag)
return tag
loop = asyncio.get_event_loop()
tasks = [coro(i) for i in range(1, 11)]
print("Get first result:")
finished, unfinished = loop.run_until_complete(
asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED))
for task in finished:
print(task.result())
print("unfinished:", len(unfinished))
print("Get more results in 2 seconds:")
finished2, unfinished2 = loop.run_until_complete(
asyncio.wait(unfinished, timeout=2))
for task in finished2:
print(task.result())
print("unfinished2:", len(unfinished2))
print("Get all other results:")
finished3, unfinished3 = loop.run_until_complete(asyncio.wait(unfinished2))
for task in finished3:
print(task.result())
loop.close()
También noté que puede proporcionar un grupo de corutinas en wait () simplemente especificando la lista:
result=loop.run_until_complete(asyncio.wait([
say(''first hello'', 2),
say(''second hello'', 1),
say(''third hello'', 4)
]))
Mientras que la agrupación en recolectar () se realiza simplemente especificando múltiples corutinas:
result=loop.run_until_complete(asyncio.gather(
say(''first hello'', 2),
say(''second hello'', 1),
say(''third hello'', 4)
))
asyncio.wait
tiene un nivel más bajo que
asyncio.gather
.
Como su nombre lo indica,
asyncio.gather
se centra principalmente en recopilar los resultados.
espera un montón de futuros y devuelve sus resultados en un orden dado.
asyncio.wait
solo espera en el futuro.
y en lugar de darle los resultados directamente, le da tareas pendientes y pendientes.
tienes que recolectar manualmente los valores.
Además, puede especificar esperar a que finalicen todos los futuros o solo el primero con
wait
.