[Python] En savoir plus sur la programmation asynchrone et les boucles d'événements

À propos de cet article

Pour être honnête, je ne peux pas vraiment parler de "ce qu'est la programmation asynchrone". Cet article décrit ce que nous avons appris sur l'un des éléments de la programmation asynchrone: le multitâche collaboratif, l''async 'de Python et les boucles d'événements.

Multitâche collaboratif et E / S asynchrones

Le multitâche collaboratif est un élément central de la programmation asynchrone et ressemble à une idée.

Lorsqu'un ordinateur exécute le multitâche, il n'utilise pas le changement de contexte du système d'exploitation. Lorsque chaque processus entre en état de veille, le processus lui-même libère volontairement le contrôle. Donne le contrôle à de nombreux autres processus exécutés en même temps. (Comparable à la signification de ** coopérative **) Le contrôle fait ici référence à la suspension et à la reprise d'un processus, ainsi qu'à l'allocation et à la libération de ressources.

Il semble que tous les processus doivent être coordonnés afin d'effectuer le multitâche en douceur.

Pour le multitâche collaboratif au niveau des applications

Où faites-vous le multitâche collaboratif? Plutôt que de coordonner plusieurs processus ou threads ** Tout le multitâche est exécuté dans un processus ou un thread. ** **

Qui contrôle la tâche? Le contrôle de plusieurs tâches est limité à une seule fonction, qui gère la coordination des tâches.

Problèmes clés du multitâche collaboratif

Dans le multitâche collaboratif, le problème le plus important est de savoir quand libérer le contrôle **. Le moment de la publication est similaire au comportement des threads. Où? ⇒ De nombreuses applications asynchrones donnent le contrôle à la boucle d'événements ou au planificateur au moment de l'instruction d'E / S. Relâchez le contrôle en attendant le traitement des E / S.

Quelle est la différence? ⇒ ** Thread ** est dû à un thread au niveau du système, ** OS peut interrompre le thread en cours d'exécution à tout moment ** et passer le contrôle à d'autres threads. En ** programmation asynchrone **, ** les tâches ne peuvent pas être interrompues par des boucles d'événements. ** (multitâche non préemptif)

Ce que vous devez garder (probablement) minimal sur la programmation asynchrone

Python s'exécute sur le système d'exploitation, en concurrence pour d'autres processus et ressources. En d'autres termes, le système d'exploitation contrôle tous les processus. Dans le cas d'une application asynchrone, le traitement est interrompu par une interruption du planificateur, mais lorsque le contrôle est retourné, il reprend à partir de l'endroit où il a été interrompu. Ce n'est pas toujours le cas avec le multithreading et le multiprocessing. Aussi, En ** multi-processus et threads **, la tâche à redémarrer est déterminée par le planificateur du système d'exploitation **. En ** programmation asynchrone **, l'application ** décide de la tâche à reprendre.

ʻAsync et ʻawait en Python

Mots réservés ʻasync et ʻawait

ʻAsync est utilisé avant l'instruction def pour définir un nouveau collout (tâche parallèle). L'exécution de la fonction collout est interrompue et reprise selon la situation définie. Même si la fonction définie par ʻasync est appelée, la fonction n'est pas exécutée sur place et un ** objet collout ** est retourné. Voici un exemple de mise en œuvre.

>>> async def asyc_hello():
...   print("Hello")
...
>>> asyc_hello()
<coroutine object asyc_hello at 0x000001D3D021C748>

Vous pouvez voir que ʻasyc_hello () retourne un objet collout au lieu de la valeur de sortie standard de print ("Hello") `. Alors, qu'est-ce qu'un objet collout? Comment dois-je gérer cela? Je vais expliquer ce domaine en gros. Vous devez créer quelque chose pour exécuter un objet collout. C'est une ** boucle d'événement **. Vous trouverez ci-dessous le code qui a créé la boucle d'événements et exécuté l'objet collout.

>>> import asyncio
>>> async def asyncio_hello():
...     print("Bonjour")
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(asyncio_hello())
Bonjour
>>> loop.close()

Créez une boucle d'événements avec ʻasyncio.get_event_loop () L'objet collout est exécuté parrun_until_complete (asyncio_hello ())`. Ensuite, j'expliquerai les bases de ce qu'est la boucle d'événements.

À propos de la boucle d'événements

Cet article n'explique pas les termes liés aux boucles d'événements. Au lieu d'expliquer la file d'attente d'événements, le répartiteur d'événements, le gestionnaire d'événements, la fonction de rappel, etc., je me suis concentré sur ce que fait le mécanisme de boucle d'événements et j'ai exprimé ce que j'ai appris dans la figure. Ci-dessous la figure. Pour plus de commodité, nous avons changé l'expression «événement» en «demande». (Pour plus de commodité, il est plus facile d'en avoir une image personnellement) イベントループ完成図1.png

A propos des objets collout

Revenons à la gestion des objets colloutés. L'objet collout sera celui qui est exécuté dans la boucle d'événements. De plus, il est mis en file d'attente dans la boucle d'événements et l'objet collout ne fait rien jusqu'à ce que son tour arrive. Le code source suivant est le code qui prépare un seul collout simple et exécute la boucle d'événements.

asyncprint.py


import asyncio

async def print_numeber(number):
    print(number)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()

    loop.run_until_complete(
        asyncio.wait([
            print_numeber(number)
            for number in range(10)
        ])
    )
    loop.close()
$ python src/asyncpritn.py
2
4
8
6
9
5
1
3
7
0

C'est le flux de base du code ci-dessus.

  1. Créez une boucle d'événements: ʻasyncio.get_event_loop () `
  2. Créez ou ajoutez une tâche: ʻasyncio.get_event_loop (). Create_task () ʻorʻasyncio.wait () `
  3. Exécutez la boucle d'événements: ʻasyncio.get_event_loop (). Run_until_complete () `
  4. Fermez explicitement la boucle d'événements: ʻasyncio.get_event_loop (). Close () `

Ensuite, c'est un exemple lorsque le mot réservé ʻawaitest ajouté à ʻasyncio.wait ().

corowait.py


import time 
import random
import asyncio

async def waiter(name):
    for _ in range(4):
        time_to_sleep = random.randint(1,3)/4
        time.sleep(time_to_sleep)
        print(
            "{}Est{}Attendu une seconde"
            "".format(name, time_to_sleep)
        )

async def main():
    await asyncio.wait([waiter("foo"), waiter("bar")])

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()
$time python corowait.py
toto vaut 0.Attendu 5 secondes
toto vaut 0.Attendu 25 secondes
toto vaut 0.Attendu 75 secondes
toto vaut 0.Attendu 25 secondes
la barre est 0.Attendu 25 secondes
la barre est 0.Attendu 75 secondes
la barre est 0.Attendu 75 secondes
la barre est 0.Attendu 25 secondes

real    0m4.416s
user    0m0.130s                                                                                      sys     0m0.013s  

ʻAwaitattend que le collout retourne l'exécution, puis libère le contrôle et le passe à la boucle d'événements jusqu'à ce qu'il finisse de s'exécuter. Ici, le traitement est bloqué par la fonctiontime.sleep (). Par conséquent, cela devient un processus synchrone et les processus sont exécutés dans l'ordre. En Python, il existe une fonction ʻasycio.sleep () pour changer le traitement bloquant en traitement non bloquant et en traitement asynchrone. En utilisant cela, il est possible d'exécuter un traitement asynchrone. Voici un exemple de code.

cowait_improved.py


import time 
import random
import asyncio

async def waiter(name):
    for _ in range(4):
        time_to_sleep = random.randint(1,3)/4
        await asyncio.sleep(time_to_sleep)
        print(
            "{}Est{}Attendu une seconde"
            "".format(name, time_to_sleep)
        )

async def main():
    await asyncio.wait([waiter("foo"), waiter("bar")])

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()
$time python corowait_improved.py
toto vaut 0.Attendu 25 secondes
la barre est 0.Attendu 75 secondes
toto vaut 0.Attendu 75 secondes
la barre est 0.Attendu 75 secondes
toto vaut 0.Attendu 75 secondes
la barre est 0.Attendu 25 secondes
toto vaut 0.Attendu 25 secondes
la barre est 0.Attendu 25 secondes

real    0m2.442s
user    0m0.161s                                                                                      sys     0m0.017s  

Les fonctions «foo» et «bar» sont exécutées en alternance, améliorant la vitesse de traitement. Cela signifie que le collout a relâché le contrôle en coopération.

Les références

https://www.atmarkit.co.jp/ait/articles/1103/23/news101_2.html Introduction à Python3 Expert Python Programming Revised 2nd Edition

Recommended Posts

[Python] En savoir plus sur la programmation asynchrone et les boucles d'événements
En savoir plus sur la programmation
À propos de Python for loop
Premiers pas avec python3 # 2 En savoir plus sur les types et les variables
Programmation avec Python et Tkinter
À propos des objets et des classes Python
À propos des variables et des objets Python
Paiza Python Primer 1 Apprendre la programmation
À propos de Python, len () et randint ()
À propos de Python et des expressions régulières
À propos des opérations Python et OS
Python # À propos de la référence et de la copie
À propos de Python sort () et reverse ()
[Introduction à Python3 Jour 1] Programmation et Python
À propos de Python dict et des fonctions triées
À propos de Python et Cython dtype
À propos de Python Pickle (cPickle) et Marshal
[Python] À propos des classes Executor et Future
À propos de Python, à partir et à l'importation, comme
Comparez les boucles de tableau Python et JavaScript
Évitez les boucles imbriquées en PHP et Python
Apprenez les mots anglais liés à Python et AI. .. ..
Apprenez les mathématiques et l'anglais grâce à la programmation (partie 1)
Une histoire sur Python pop and append
Parler d'anciennes et de nouvelles classes en Python
À propos de _ et __
Apprenez les mathématiques et l'anglais grâce à la programmation (partie 2)
Parler des attributs de classe Python et des métaclasses
Qu'est-ce que la «programmation fonctionnelle» et «orientée objet»? Édition Python
Pensez aux recherches de priorité de profondeur et de priorité de largeur en Python
À propos de la différence entre "==" et "is" en python
Une histoire sur la modification de Python et l'ajout de fonctions
À propos des copies superficielles et profondes de Python / Ruby
À propos des tranches Python
À propos de la notation d'inclusion de python
Note de programmation Python
À propos de Python tqdm.
À propos de python, classe
À propos de l'héritage Python
Programmation avec Python
À propos de python, range ()
À propos de la référence Python
À propos des décorateurs Python
[Python] À propos du multi-processus
Apprenez les gestes python
Traitement asynchrone de Python ~ Comprenez parfaitement async et attendez ~
À propos de la création et de la modification de thèmes personnalisés pour Python IDLE
Paiza Python Primer 2: Apprenez les opérateurs de branchement conditionnel et de comparaison
Apprenez le traitement / collouts asynchrones Python en comparant avec Node.js
Découvrez la fonction d'impression et les chaînes de python pour les débutants.
[Python] Chapitre 01-02 À propos de Python (Exécution et installation de l'environnement de développement)