web-dev-qa-db-fra.com

Asyncio.gather vs asyncio.wait

asyncio.gather et asyncio.wait semblent avoir des utilisations similaires: j'ai un tas de choses asynchrones que je veux exécuter/attendre (pas nécessairement en attente pour finir avant le prochain). Ils utilisent une syntaxe différente et diffèrent par certains détails, mais il me semble très peu pythonique de disposer de deux fonctions qui se chevauchent si énormément. Qu'est-ce que je rate?

98
Claude

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

asyncio.gather()

Renvoie une instance future, permettant le regroupement de tâches à 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()

Prise en charge de l'attente d'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()
121
Udi

asyncio.wait est plus faible que asyncio.gather.

Comme son nom l'indique, asyncio.gather se concentre principalement sur la collecte des résultats. il attend une série de contrats à terme et renvoie ses résultats dans un ordre donné.

asyncio.wait n'attend que l'avenir. et au lieu de vous donner directement les résultats, cela donne des tâches terminées et en attente. vous devez collecter manuellement les valeurs.

De plus, vous pouvez spécifier d'attendre que tous les futurs soient terminés ou que le premier avec wait.

26
ospider

J'ai aussi remarqué que vous pouvez fournir un groupe de coroutines à 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)
    ]))

Considérant que le regroupement dans la collecte () est 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)
    ))
10
Johny Ebanat