web-dev-qa-db-fra.com

Faire async pour les boucles dans Python

Le code suivant sort comme suit:

1 sec delay, print "1", 
1 sec delay, print "2", 
1 sec delay, print "1", 
1 sec delay, print "2"

Comment peut-il être modifié pour fonctionner comme ceci:

1 sec delay, print "1", print "1",
1 sec delay, print "2", print "2"

Je voudrais qu'il s'exécute pour que les deux instances de la boucle for commencent à s'exécuter en même temps. À mesure que chaque instance s'exécute, elles rencontrent la première fonction () en même temps, puis la seconde fonction () en même temps, imprimant ainsi dans l'ordre mentionné ci-dessus.

Code:

import asyncio

async def first():
    await asyncio.sleep(1)
    return "1"

async def second():
    await asyncio.sleep(1)
    return "2"

async def main():     
    for i in range(2):
      result = await first()
      print(result)
      result2 = await second()
      print(result2)


loop = asyncio.get_event_loop()
loop.run_until_complete(main())
3
Canis Lobo

En regardant la sortie souhaitée, il semble que le but est de laisser l'itération individuelle telle qu'elle est - c'est-à-dire d'exécuter first et second séquentiellement - mais d'exécuter les deux itérations de boucle en parallèle.

En supposant que vous souhaitiez seulement modifier main(), cela pourrait être réalisé comme ceci:

async def main():
    async def one_iteration():
        result = await first()
        print(result)
        result2 = await second()
        print(result2)
    coros = [one_iteration() for _ in range(2)]
    await asyncio.gather(*coros)

Au lieu d'itérer en séquence, ce qui précède crée une coroutine pour chaque tâche d'itération et utilise asyncio.gather pour exécuter toutes les itérations en parallèle.

Notez que la simple création d'une coroutine ne démarre pas son exécution, donc un grand nombre de coros ne bloquera pas la boucle d'événement.

9
user4815162342

Avec la bibliothèque aysncio, vous pouvez utiliser aysncio.gather ()

loop.run_until_complete(asyncio.gather(
  first(),
  second()
))

Cela peut être utile si vous envoyez également des requêtes HTTP en parallèle:

loop.run_until_complete(asyncio.gather(
  request1(),
  request2()
))
2
Wajih Qazi

Pour exécuter les deux fonctions simultanément, vous pouvez utiliser gather . Cependant, les résultats vous seront fournis dans l'ordre que vous leur fournissez. Ainsi, par exemple, si vous le faites

results = await asyncio.gather(first(), second())

Ensuite, vous récupérerez [the result of first(), the result of second()]. Si vous voulez faire quelque chose chaque fois que chacun retourne, vous devez utiliser Tasks explicitement et ajouter des rappels .

1
Nick Chapman