web-dev-qa-db-fra.com

Django - async_to_sync vs asyncio.run

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?

5
Max Malysh

Différences

  1. 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.

  2. Selon documentation , un appelable de async_to_sync fonctionne dans un sous-thread .

  3. 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 .

1
Artemiy Rodionov