You made faire_toutes_les_requetes_sans_bloquer
an awaitable function, a coroutine, by usingasync def
.
When you call an awaitable function, you create a new coroutine object. The code inside the function won't run until you then await on the function or run it as a task:
>>> async def foo():
... print("Running the foo coroutine")
...
>>> foo()
<coroutine object foo at 0x10b186348>
>>> import asyncio
>>> asyncio.run(foo())
Running the foo coroutine
You want to keep that function synchronous, because you don't start the loop until inside that function:
def faire_toutes_les_requetes_sans_bloquer():
loop = asyncio.get_event_loop()
# ...
loop.close()
print("Fin de la boucle !")
However, you are also trying to use a aiophttp.ClientSession()
object, and that's an asynchronous context manager, you are expected to use it with async with
, not just with
, and so has to be run in aside an awaitable task. If you use with
instead of async with
a TypeError("Use async with instead")
exception will be raised.
That all means you need to move the loop.run_until_complete()
call out of your faire_toutes_les_requetes_sans_bloquer()
function, so you can keep that as the main task to be run; you can call and await on asycio.gather()
directly then:
async def faire_toutes_les_requetes_sans_bloquer():
async with aiohttp.ClientSession() as session:
futures = [requete_sans_bloquer(x, session) for x in range(10)]
await asyncio.gather(*futures)
print("Fin de la boucle !")
print("Non bloquant : ")
start = datetime.datetime.now()
loop.run(faire_toutes_les_requetes_sans_bloquer())
exec_time = (datetime.datetime.now() - start).seconds
print(f"Pour faire 10 requêtes, ?a prend {exec_time}s
")
I used the new asyncio.run()
function (Python 3.7 and up) to run the single main task. This creates a dedicated loop for that top-level coroutine and runs it until complete.
Next, you need to move the closing )
parenthesis on the await resp.json()
expression:
uid = (await response.json())['uuid']
You want to access the 'uuid'
key on the result of the await
, not the coroutine that response.json()
produces.
With those changes your code works, but the asyncio version finishes in sub-second time; you may want to print microseconds:
exec_time = (datetime.datetime.now() - start).total_seconds()
print(f"Pour faire 10 requêtes, ?a prend {exec_time:.3f}s
")
On my machine, the synchronous requests
code in about 4-5 seconds, and the asycio code completes in under .5 seconds.