Asyncio.gather vs asyncio.wait


150

asyncio.gathery asyncio.waitparece 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?

Respuestas:


178

Aunque es 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 group2.cancel()o incluso all_groups.cancel(). Véase 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()

55
"La forma de asterisco único (* args) se usa para pasar una lista de argumentos de longitud variable sin palabras clave, y la forma de asterisco doble se usa para pasar una lista de argumentos de longitud variable sin
— palabras clave

41

asyncio.waites más bajo nivel que asyncio.gather.

Como su nombre lo indica, asyncio.gatherse centra principalmente en recopilar los resultados. espera en un montón de futuros y devuelve sus resultados en un orden determinado.

asyncio.waitsolo 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.


Usted dice: it waits on a bunch of futures and return their results in a given order. ¿Qué pasa si tengo 10000000000000 tareas y todas ellas devuelven datos grandes? Todo el resultado hará el boom de la memoria?
— Kingname

@Kingname ..wat
— Matt Joiner

14

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)
    ))

20
Las listas también se pueden usar con gather(), por ejemplo:asyncio.gather(*task_list)
— tehfink

1
Así pueden los generadores
— Jab

¿Cómo puedes usar esta reunión sin bloquear el resto del script?
— thebeancounter
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.