Asyncio.gather contre asyncio.wait

150

asyncio.gatheret asyncio.waitsemblent avoir des utilisations similaires: j'ai un tas de choses asynchrones que je veux exécuter / attendre (pas nécessairement attendre que l'une se termine avant que la suivante ne commence). Ils utilisent une syntaxe différente, et diffèrent dans certains détails, mais il me semble très antipythonique d'avoir 2 fonctions qui ont un si énorme chevauchement de fonctionnalités. Qu'est-ce que je rate?

Claude
la source

Réponses:

178

Bien que similaire dans les cas généraux ("exécuter et obtenir des résultats pour de nombreuses tâches"), chaque fonction a des fonctionnalités spécifiques pour d'autres cas:

asyncio.gather()

Renvoie une instance Future, permettant le regroupement de tâches de haut niveau:

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)

Toutes les tâches d'un groupe peuvent être annulées en appelant group2.cancel()ou même all_groups.cancel(). Voir aussi .gather(..., return_exceptions=True),

asyncio.wait()

Prend en charge l'attente d'être arrêté après la première tâche ou après un délai spécifié, permettant une précision des opérations de niveau inférieur:

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()
Udi
la source
5
"La forme d'astérisque unique (* args) est utilisée pour transmettre une liste d'arguments de longueur variable sans mots clés, et la forme d'astérisque double est utilisée pour transmettre une liste d'arguments de longueur variable avec
mots clés
41

asyncio.waitest un niveau plus bas que asyncio.gather.

Comme son nom l'indique, asyncio.gatherse concentre principalement sur la collecte des résultats. il attend un tas de contrats à terme et renvoie leurs résultats dans un ordre donné.

asyncio.waitattend juste sur l'avenir. et au lieu de vous donner les résultats directement, il donne les tâches terminées et en attente. vous devez collecter manuellement les valeurs.

De plus, vous pouvez spécifier d'attendre la fin de tous les contrats à terme ou juste le premier avec wait.

ospider
la source
Vous dites: it waits on a bunch of futures and return their results in a given order. Que faire si j'ai 10000000000000 tâches et que toutes renvoient des données volumineuses? tout le résultat fera le boom de la mémoire?
Kingname
@Kingname ..wat
Matt Joiner
14

J'ai également remarqué que vous pouvez fournir un groupe de coroutines dans wait () en spécifiant simplement la liste:

result=loop.run_until_complete(asyncio.wait([
        say('first hello', 2),
        say('second hello', 1),
        say('third hello', 4)
    ]))

Alors que le regroupement dans Collect () se fait en spécifiant simplement plusieurs coroutines:

result=loop.run_until_complete(asyncio.gather(
        say('first hello', 2),
        say('second hello', 1),
        say('third hello', 4)
    ))
Johny Ebanat
la source
20
Les listes peuvent également être utilisées avec gather(), par exemple:asyncio.gather(*task_list)
tehfink
1
Alors, les générateurs peuvent
Jab
Comment pouvez-vous utiliser ce regroupement sans bloquer le reste du script?
thebeancounter