Avec ce code asyncio, mon tuteur dit que toutes les coroutines (ici les 50 "fetch_page") s'arrêtent d'abord au premier async with et attendent, puis toutes reprennent à partir de là et s'arrêtent au deuxième async with, puis finalement ils reviennent tous.

import aiohttp
import asyncio

async def fetch_page(url):
    print(1)
    async with aiohttp.ClientSession() as session:
       print(2)
        async with session.get(url) as response:
            print(3)
            return response.status

loop = asyncio.get_event_loop()    
tasks = [fetch_page('http://google.com') for i in range(50)]
loop.run_until_complete(asyncio.gather(*tasks))

Je débogue ça, et je dois dire qu'il a tort. Pendant le débogage, je vois toutes les coroutines aller séquentiellement au deuxième async with, où elles s'arrêtent toutes. Ensuite, une fois que les 50 coroutines ont repris, elles font le session.get(url) et reviennent.

Mais pourquoi toutes les coroutines ne s'arrêtent-elles pas au premier async with?

Sortie d'impression: "1 2 1 2 1 2 ... 3 3 3 ...", au lieu de "1 1 1 ... 2 2 2 ... 3 3 3 ..."

1
trogne 14 mars 2019 à 22:35

2 réponses

Meilleure réponse

Il manque une petite info ici:

Asyncio est une bibliothèque monothread basée sur la boucle d'événements.

Ce qui se passe dans ce cas est que aiohttp.ClientSession() as session n'est pas une opération coûteuse d'E / S, son exécution ne prend pas de temps, c'est pourquoi elle est exécutée immédiatement avant même que l'itérateur ne passe au cycle de boucle suivant.

Pourquoi 3333 est-il imprimé en dernier? parce que vous faites une E / S qui prend du temps, plus qu'une boucle de 50 fois.

Pour plus de détails, lisez ici : asyncio python doc

1
Ramy M. Mousa 15 mars 2019 à 10:54

Mais pourquoi toutes les couroutines ne s'arrêtent pas au premier async with ?

Comme tout autre await, un async with ne garantit pas que la coroutine y sera suspendue, mais il permet à la coroutine de se suspendre s'il y a une raison de le faire. Dans ce cas, la simple création d'un ClientSession est une opération qui peut être effectuée sans suspendre aucune coroutine, de sorte que chacun d'eux continue simplement.

La saisie du second async with doit obtenir un objet de réponse, ce qui nécessite que la requête ait été envoyée et les en-têtes HTTP reçus. Exécutées sur un socket non bloquant, certaines de ces opérations signaleront que les données ne sont pas immédiatement disponibles (car elles doivent atteindre le serveur, et le serveur doit élaborer une réponse, puis la réponse doit nous revenir) , et asyncio gère cela en suspendant la coroutine. C'est pourquoi le second async with est pratiquement assuré de suspendre chaque coroutine qui l'atteint.

2
user4815162342 14 mars 2019 à 21:18