J'utilise un module tiers pour récupérer les données d'une API. Je voudrais simplement attendre de manière asynchrone le module pour renvoyer les données, ce qui prend parfois plusieurs secondes et gèle mon application. Cependant, lorsque j'essaye d'attendre un appel de ce module, je reçois le TypeError:
TypeError: object dict can't be used in 'await' expression
import thirdPartyAPIwrapper
async def getData():
retrienveData = await thirdPartyAPIWrapper.data()
return await retrieveData
def main():
loop = asncio.get_event_loop()
data = loop.run_until_complete(getData())
loop.close
return data
Pourquoi ne puis-je pas attendre un type ('dict')? Y a-t-il un moyen de contourner cela? Si async/wait with asyncio ne fonctionnera pas avec un module tiers qui ne renvoie pas de coroutine, quelles sont mes autres options?
Seules des fonctions asynchrones (définies avec async def
) peuvent être attendues. L’idée générale est que de telles fonctions sont écrites de manière spéciale, ce qui permet de les exécuter (await
) sans bloquer la boucle d’événement.
Si vous voulez obtenir le résultat d'une fonction commune (définie avec def
) dont l'exécution prend beaucoup de temps, vous avez les options suivantes:
Habituellement, vous voulez choisir une deuxième option.
Voici un exemple de la façon de le faire:
import asyncio
import time
from concurrent.futures import ThreadPoolExecutor
_executor = ThreadPoolExecutor(1)
def sync_blocking():
time.sleep(2)
async def hello_world():
# run blocking function in another thread,
# and wait for it's result:
await loop.run_in_executor(_executor, sync_blocking)
loop = asyncio.get_event_loop()
loop.run_until_complete(hello_world())
loop.close()
S'il vous plaît, lisez cette réponse sur le fonctionnement de l'asyncio. Je pense que ça vous aidera beaucoup.
Comme thirdPartyAPIWrapper.data()
est une fonction de synchronisation normale, vous devriez l'appeler dans un autre thread.
Il existe une fonction d'assistance pour cela dans une bibliothèque asgiref
.
Supposons que nous ayons une fonction de blocage avec un argument:
import asyncio
import time
from asgiref.sync import sync_to_async
def blocking_function(seconds: int) -> str:
time.sleep(seconds)
return f"Finished in {seconds} seconds"
async def main():
seconds_to_sleep = 5
function_message = await sync_to_async(blocking_function)(seconds_to_sleep)
print(function_message)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Il existe également une fonction d'assistance async_to_sync
dans cette bibliothèque.