I am trying to learn to use asyncio in Python to optimize scripts.
My example returns a coroutine was never awaited
warning, can you help to understand and find how to solve it?
import time
import datetime
import random
import asyncio
import aiohttp
import requests
def requete_bloquante(num):
print(f'Get {num}')
uid = requests.get("https://httpbin.org/uuid").json()['uuid']
print(f"Res {num}: {uid}")
def faire_toutes_les_requetes():
for x in range(10):
requete_bloquante(x)
print("Bloquant : ")
start = datetime.datetime.now()
faire_toutes_les_requetes()
exec_time = (datetime.datetime.now() - start).seconds
print(f"Pour faire 10 requêtes, ça prend {exec_time}s\n")
async def requete_sans_bloquer(num, session):
print(f'Get {num}')
async with session.get("https://httpbin.org/uuid") as response:
uid = (await response.json()['uuid'])
print(f"Res {num}: {uid}")
async def faire_toutes_les_requetes_sans_bloquer():
loop = asyncio.get_event_loop()
with aiohttp.ClientSession() as session:
futures = [requete_sans_bloquer(x, session) for x in range(10)]
loop.run_until_complete(asyncio.gather(*futures))
loop.close()
print("Fin de la boucle !")
print("Non bloquant : ")
start = datetime.datetime.now()
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\n")
The first classic part of the code runs correctly, but the second half only produces:
synchronicite.py:43: RuntimeWarning: coroutine 'faire_toutes_les_requetes_sans_bloquer' was never awaited
Rohit Patel
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:
You want to keep that function synchronous, because you don’t start the loop until inside that function:
However, you are also trying to use a
aiophttp.ClientSession()
object, and that’s an asynchronous context manager, you are expected to use it withasync with
, not justwith
, and so has to be run in aside an awaitable task. If you usewith
instead ofasync with
aTypeError("Use async with instead")
exception will be raised.That all means you need to move the
loop.run_until_complete()
call out of yourfaire_toutes_les_requetes_sans_bloquer()
function, so you can keep that as the main task to be run; you can call and await onasycio.gather()
directly then: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 theawait resp.json()
expression:You want to access the
'uuid'
key on the result of theawait
, not the coroutine thatresponse.json()
produces.With those changes your code works, but the asyncio version finishes in sub-second time; you may want to print microseconds:
On my machine, the synchronous
requests
code in about 4-5 seconds, and the asycio code completes in under .5 seconds.