Apprenez le traitement / collouts asynchrones Python en comparant avec Node.js

Python est un langage de style qui implémente un traitement asynchrone en important le module ʻasyncio` et en définissant des coroutines. Un ** collout ** est une structure qui permet d'interrompre puis de reprendre le traitement, contrairement au ** sous-programme **, qui est une structure qui ne s'arrête pas tant que le traitement n'est pas terminé.

Cette fois, concentrons-nous sur la manière dont le traitement asynchrone de Python est écrit différemment de «Promise» et «async / await» de Node.js, que je connais depuis longtemps. pense.

Notez que le code source Python est largement conforme à la documentation officielle Coroutines and Tasks.

Corroutine

En Python, l'instruction ʻasync def` définit un collout.

Python


import asyncio

async def main():
    print('hello')
    await asyncio.sleep(1)
    print('world')

asyncio.run(main())

Ceci est un exemple d'impression de "monde" une seconde après l'impression de "bonjour". Vous pouvez utiliser ʻawaitdans le collout. Ceci est un exemple typique de traitement asynchrone, où ʻawait asyncio.sleep (1)attend la résolution du traitement pendant 1 seconde puis démarre le traitement suivant.

Qu'en est-il de Node.js? Premièrement, Node.js n'a pas de fonction asynchrone intégrée comme ʻasyncio.sleep () `de Python,

function sleep(sec) {
  return new Promise(resolve => {
    setTimeout(resolve, timeout=sec*1000);
  })
}

(Ci-après, la définition de cette fonction «sleep» est omise dans le code source de Node.js). Ensuite, vous pouvez écrire comme suit.

Node.js


async function main() {
  console.log('hello');
  await sleep(1);
  console.log('world');
}

main();

En comparant les deux, le traitement asynchrone collouté de Python n'appelle pas simplement le point d'entrée de niveau supérieur main (), mais ʻasyncio.run (main ()) , ʻasyncio. La différence est que vous devez faire attention à l'exécuter dans l'argument de .run () .

Traitement série

L'organisation de l'attente entraînera un traitement en série.

Python


import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at {time.strftime('%X')}")

    await say_after(1, 'hello')
    await say_after(2, 'world')

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

Ceci est un exemple d'attente pendant 1 seconde, puis d'impression de «bonjour», puis d'attente de 2 secondes supplémentaires, puis d'impression de «monde». Écrit dans Node.js, cela devrait ressembler à ceci:

Node.js


async function say_after(delay, what) {
  await sleep(delay);
  console.log(what);
}

async function main() {
  console.log(`started at ${new Date().toTimeString()}`);

  await say_after(1, 'hello');
  await say_after(2, 'world');

  console.log(`finished at ${new Date().toTimeString()}`);
}

main();

Cela ressemble au même, donc c'est facile à comprendre.

Traitement parallèle

Les tâches vous permettent d'exécuter des collouts en parallèle en Python.

Python


import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

    print(f"started at {time.strftime('%X')}")

    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

Dans cet exemple, contrairement à l'exemple précédent, l'opération "attendre 2 secondes puis sortir" monde "" est effectuée en même temps que l'opération "attendre 1 seconde puis sortir" bonjour "", donc 1 que l'exemple précédent. Cela se terminera une seconde plus tôt. En Python, ʻasyncio.create_task () `vous permet d'envelopper un collout en tant que tâche et de planifier son exécution.

Écrit dans Node.js, cela devrait ressembler à ceci:

Node.js


async function say_after(delay, what) {
  await sleep(delay);
  console.log(what);
}

async function main() {
  const task1 = say_after(1, 'hello');
  const task2 = say_after(2, 'world');

  console.log(`started at ${new Date().toTimeString()}`);

  await Promise.all([task1, task2]);

  console.log(`finished at ${new Date().toTimeString()}`);
}

main();

Pour Node.js, vous pouvez utiliser Promise.all ().


Regardons un autre exemple.

Python


import asyncio

async def factorial(name, number):
    f = 1
    for i in range(2, number + 1):
        print(f"Task {name}: Compute factorial({i})...")
        await asyncio.sleep(1)
        f *= i
    print(f"Task {name}: factorial({number}) = {f}")

async def main():
    await asyncio.gather(
        factorial("A", 2),
        factorial("B", 3),
        factorial("C", 4),
    )

asyncio.run(main())

Il s'agit d'une fonction qui calcule la puissance en retardant la multiplication de 1 seconde à chaque fois. Cette fois, ʻasyncio.gather () `est sorti, qui planifie également l'argument coroutine comme une tâche.

Écrit dans Node.js, cela devrait ressembler à ceci:

Node.js


async function factorial(name, number) {
  let f = 1;
  for (let i=2;i<=number;++i) {
    console.log(`Task ${name}: Compute factorial(${i})...`);
    await sleep(1);
    f *= i;
  }
  console.log(`Task ${name}: factorial(${number}) = ${f}`);
}

async function main() {
  await Promise.all([
    factorial("A", 2),
    factorial("B", 3),
    factorial("C", 4)
  ]);
}

main();

temps libre

Dans le traitement asynchrone Python, vous pouvez utiliser ʻasyncio.wait_for () `pour le traiter comme un timeout si le traitement n'est pas terminé dans un certain laps de temps.

Python


import asyncio

async def eternity():
    await asyncio.sleep(3600)
    print('yay!')

async def main():
    try:
        await asyncio.wait_for(eternity(), timeout=1.0)
    except asyncio.TimeoutError:
        print('timeout!')

asyncio.run(main())

Par exemple, dans l'exemple ci-dessus, la fonction ʻeternity () `qui dort pendant 3600 secondes expire en fait après 1 seconde sans attendre 3600 secondes.

Je ne pense pas qu'il existe un moyen concis d'implémenter cela dans Node.js (pour autant que je sache).

Certainement, si vous utilisez Promise.race (),

await Promise.race(eternity(), timeout(1.0))
  .catch(err => {
    console.log('timeout!');
  })

(Timeout (sec) est une fonction qui renvoie rejeter après sec secondes). Cependant, dans cette implémentation, même après 1 seconde, "timeout!" S'affiche, ʻeternity () `continue d'attendre.

Voir aussi: Use Promise.race to Timeout Promises

Caveat: Cleanup The timeout does not cause the other promise to clean up or cancel. For example, if a database-write promise were to be Promise.race ‘d against a timeout, and if the timeout completed first, then the database write operation would still be running and may (eventually) succeed, but the rest of your application will think it failed. Make sure to introduce logic to cancel the operation in case your application initiates a timeout. Handling cleanup and canceling logic is a tricky subject, as the feature is not built into JavaScript.

Dans cet esprit, il est assez pratique en Python de pouvoir simplement écrire des interruptions dans le traitement asynchrone.

Recommended Posts

Apprenez le traitement / collouts asynchrones Python en comparant avec Node.js
Apprenez Python avec ChemTHEATER
Traitement de la communication par Python
Traitement d'image avec Python
100 coups de traitement du langage avec Python 2015
"Traitement Apple" avec OpenCV3 + Python3
Traitement du signal acoustique avec Python (2)
Traitement du signal acoustique avec Python
Traitement asynchrone (threading) en python
[Python] Traitement d'image avec scicit-image
Traitez d'énormes fichiers Excel avec Python pour améliorer la productivité
[Python] Traitement parallèle facile avec Joblib
100 traitements de langage avec Python
Paiza Python Primer 3: Apprendre le traitement des boucles
Apprenez Python en dessinant (Turtle Graphics)
100 traitements de langage avec Python (chapitre 3)
Traitement d'image avec la binarisation Python 100 knocks # 3
[Python] Requête asynchrone avec async / await
100 traitement d'image par Python Knock # 2 Échelle de gris
100 Language Processing Knock Chapitre 1 par Python
Bases du traitement d'images binarisées par Python
Obtenez des informations sur la propriété en grattant avec python
Traitement d'image par Python 100 knock # 10 filtre médian
Premiers pas avec python3 # 1 Apprenez les connaissances de base
Réintroduction aux décorateurs Python ~ Apprenons les décorateurs par type ~
Communication socket et traitement multi-thread par Python
Traitement d'image par le remplacement du canal Python 100 Knock # 1
Enregistrer la vidéo image par image avec Python OpenCV
100 traitement d'image avec Python Knock # 8 Max Pooling
Effectuez périodiquement un traitement arbitraire avec Python Twisted
Laissez Heroku faire le traitement en arrière-plan avec Python
100 traitements de langage avec Python (chapitre 2, partie 2)
Échelle de gris par matrice-Reinventor of Python image processing-
3. Traitement du langage naturel par Python 2-1. Réseau de co-occurrence
Traitement d'image par Python 100 knock # 12 motion filter
Traitement d'image par Python 100 Knock # 6 Traitement de réduction de couleur
3. Traitement du langage naturel par Python 1-1. Word N-gram
Apprendre Python! Comparaison avec Java (fonction de base)
100 traitements de langage avec Python (chapitre 2, partie 1)
Dessin avec Matrix-Reinventor of Python Image Processing-
Traitez facilement des images en Python avec Pillow
Organisez les données séparées par dossier avec Python
Apprenez le modèle de conception "Singleton" avec Python
Traitement d'image avec Python 100 knocks # 7 pooling moyen
Traitement d'image léger avec Python x OpenCV
Apprenez le modèle de conception "Façade" avec Python
Traitement d'image par Python 100 knock # 9 Filtre Gaussien
Démarrer avec Python avec 100 coups sur le traitement du langage
Traitement asynchrone en Python: référence inverse asyncio
Classement des numéros de stock par balise Qiita avec python
3. Traitement du langage naturel par Python 2-2. Réseau de co-occurrence [mecab-ipadic-NEologd]
Comment faire un traitement parallèle multicœur avec python
Traitement d'image à partir de zéro avec python (5) Transformation de Fourier
Dessinez un graphique en traitant avec Pandas groupby
[Python] J'ai joué avec le traitement du langage naturel ~ transformers ~
Traitement d'image à partir de zéro avec python (4) Extraction de contour
Que comparez-vous avec Python et ==?
Traitement asynchrone avec Arduino (traitement des demandes de traitement de Linux de manière asynchrone)
Traitement d'image par filtre de lissage Python 100 knock # 11 (filtre moyen)
Traitement parallèle sans signification profonde en Python