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?

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

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.


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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.