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