Convertir l'API asynchrone de style callback en async / await en Python

Aperçu

Depuis Python 3.5, async / await est disponible pour la programmation asynchrone. Cependant, de nombreuses bibliothèques existantes ont une API asynchrone de type callback traditionnelle et async / await ne peut pas être appliqué tel quel. Par conséquent, nous allons convertir une telle API de type de rappel dans un formulaire qui peut être utilisé avec async / await.

Exemple d'API asynchrone de type callback

Ajoute les arguments a et b sur un autre thread et renvoie le résultat dans un rappel Considérez la méthode async_add ci-dessous.

import time
import threading

def async_add(a, b, callback):
    def run():
        time.sleep(1)
        callback(a + b)
    thread = threading.Thread(target=run)
    thread.start()

Utilisons ceci pour faire un calcul 1 + 2 + 3. Ce sera comme suit.

async_add(1, 2, lambda result1: \
        async_add(result1, 3, lambda result2: \
                print(result2)))

C'est compliqué car les rappels sont imbriqués. Je voudrais conclure ceci afin que je puisse utiliser await pour écrire une image comme celle-ci:

result1 = await awaitable_async_add(1, 2)
result2 = await awaitable_async_add(result1, 3)
print(result2)

la mise en oeuvre

code

import time
import threading
import asyncio

def async_add(a, b, callback):
    def run():
        time.sleep(1)
        callback(a + b)
    thread = threading.Thread(target=run)
    thread.start()

def awaitable_async_add(a, b, loop):
    f = asyncio.Future() # (1)
    def callback(result):
        loop.call_soon_threadsafe(
                lambda: f.set_result(result)) #(2)
    async_add(a, b, callback) # (1)
    return f # (1)

async def exec(loop):
    result1 = await awaitable_async_add(1, 2, loop)
    result2 = await awaitable_async_add(result1, 3, loop)
    print(result2)

loop = asyncio.get_event_loop() # (3)
loop.run_until_complete(exec(loop)) # (3)
loop.stop()

Résultat d'exécution

6

Commentaire

(1) Lorsque la méthode awaitable_async_add est appelée, l'exécution de la méthode async_add est lancée et l'objet asyncio.Future est renvoyé immédiatement. À ce stade, le processus de calcul n'est pas encore terminé.

(2) Le rappel est appelé lorsque le processus de calcul est terminé. En appelant la méthode set_result () de l'objet asyncio.Future avec le résultat du traitement comme argument, l'objet asyncio.Future est notifié de la fin du traitement et le résultat du calcul est renvoyé.

(3) Acquérir une boucle d'événements et exécuter le processus jusqu'à ce que le processus asynchrone soit terminé.

Une chose à noter ici est loop.call_soon_threadsafe dans (2). Si vous essayez d'appeler f.set_result directement comme indiqué ci-dessous, une erreur se produit.

    def callback(result):
        f.set_result(result)

Résultat d'exécution

RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one

Cette erreur est due au fait que la méthode set_result est appelée sur un thread différent de la boucle d'événements exécutée dans (3). Comme asyncio.Future n'est pas thread-safe, la méthode set_result doit toujours être appelée dans le même thread que la boucle d'événements. Par conséquent, en passant le traitement en tant que rappel à la méthode call_soon_threadsafe de la boucle d'événements, set_result est appelé dans la boucle d'événements.

référence

https://docs.python.org/3.6/library/asyncio.html

Recommended Posts

Convertir l'API asynchrone de style callback en async / await en Python
Convertir Markdown en PDF en Python
Masquer les websockets async / attendent dans Python3
[Python] Requête asynchrone avec async / await
Convertir un fichier psd en png en Python
Convertir de Markdown en HTML en Python
Convertir une URL absolue en URL relative en Python
Convertissez des PDF en images en masse avec Python
Convertir un float exponentiel en str en Python
Convertir le code de maillage cubique en WKT en Python
python async / attend curio
API C en Python 3
Convertir la date et l'heure zonées en temps Unixtime dans Python2.7
Comment convertir / restaurer une chaîne avec [] en python
Convertir le tableau NumPy "ndarray" en lilt en Python [tolist ()]
Convertir le masque de réseau de notation CIDR en notation décimale à points en Python
Comment convertir des nombres à virgule flottante en nombres binaires en Python
Convertissez l'image au format .zip en PDF avec Python
Convertir / renvoyer des objets de classe au format JSON en Python
Traitement asynchrone de Python ~ Comprenez parfaitement async et attendez ~
[Python] Création d'une méthode pour convertir la base en 1 seconde
Convertir le type d'entité Webpay en type Dict (récursivement en Python)
Hit API de Mastodon en Python
Scraping à l'aide de Python 3.5 async / await
Pour vider stdout en Python
Convertir numpy int64 en python int
[Python] Convertir la liste en Pandas [Pandas]
Connectez-vous au site Web en Python
Traitement asynchrone (threading) en python
Convertir le projet Scratch en Python
[Python] Convertir Shift_JIS en UTF-8
Convertir la notation CIDR en Python
Parler avec Python [synthèse vocale]
API Blender Python dans Houdini (Python 3)
Comment développer en Python
Convertir le code python 3.x en python 2.x
Publier sur Slack en Python
Benchmark des performances de thread léger utilisant async / await implémenté dans Python 3.5
J'ai essayé de créer une API list.csv avec Python à partir de swagger.yaml
Convertir l'image passée à Jason Stay Samlike en Python en ASCII Art
Convertir un fichier Excel en texte en Python à des fins de comparaison
Appelez l'API github en python pour obtenir des informations sur la demande d'extraction
Un moyen simple d'accéder à l'API produit Amazon en Python
Déterminez le format de la date et de l'heure avec Python et convertissez-le en Unixtime
[Python] Comment faire PCA avec Python
Obtenir l'API arXiv en Python
Comment collecter des images en Python
Frappez l'API Sesami en Python
Convertir des fichiers écrits en python, etc. en pdf avec la coloration syntaxique
Comment utiliser SQLite en Python
Workflow pour convertir une formule (image) en python
Convertir la liste en DataFrame avec python
Lisez le binaire big endian en Python et convertissez-le en ndarray
Essayez de calculer Trace en Python
Comment convertir 0,5 en 1056964608 en un seul coup
Accédez à l'API New Relic en Python pour obtenir l'état du serveur
Créez Gmail en Python sans utiliser l'API
Python> liste> Convertir une double liste en une seule liste
Accédez à l'API Web en Python
Comment utiliser Mysql avec python