Nous pouvons utiliser les deux fonctions pour exécuter n'importe quelle fonction asynchrone de manière synchrone:
import asyncio
from asgiref.sync import async_to_sync
asyncio.run(asyncio.sleep(1))
async_to_sync(asyncio.sleep)(1)
Quelle est la différence? Pouvons-nous toujours utiliser asyncio.run
au lieu de async_to_sync
?
Ils ont des objectifs différents. async_to_sync
transforme un attendable en appelable synchrone, et asyncio.run
exécute une coroutine et renvoie le résultat.
Selon documentation , un appelable de async_to_sync
fonctionne dans un sous-thread .
async_to_sync
ne crée pas de boucle d'événement par thread dans le cas où vous êtes à l'intérieur d'un code synchrone produit par sync_to_async
et s'exécutant dans du code asynchrone. Il réutilise une boucle de code asynchrone. Prenons un exemple:
import asyncio
from asgiref.sync import async_to_sync, sync_to_async
async def running(n):
return [await sync_to_async(sync)(i) for i in range(n)]
def sync(n):
# it will create a new loop for every call
return asyncio.run(from_sync(n))
async def from_sync(n):
return n
print("Result:", asyncio.run(running(3)))
Celui-ci exécutera 4 boucles: 1 pour appeler running
et 3 pour appeler from_sync
.
Si nous utilisons async_to_sync
au lieu de asyncio.run
à l'intérieur de sync
nous réduirons le nombre de boucles à 1 pour appeler running
.
Pour le voir, vous pouvez envelopper new_event_loop
fonction:
def print_deco(fn, msg):
def inner(): res = fn(); print(msg, res); return res
return inner
p = asyncio.get_event_loop_policy()
p.new_event_loop = print_deco(p.new_event_loop, "NEW EVENT LOOP:")
Vous pouvez trouver une explication détaillée dans ce post .