Un programme est une succession d'instructions qui s'exécutent plus ou moins rapidement :
Ce mode de programmation est un appelé programmation synchrone.
Le mode programmation asynchrone permet alors de lancer l'exécution d'une instruction et, sans attendre la fin de l'exécution de celle-ci, de lancer l'exécution d'une autre instruction.
Cela est utile pour des instructions qui s'exécutent lentement comme la récupération ou l'écriture de données depuis le réseau ou sur le disque dur (les entrée/sorties) et que l'on souhaite na pas bloquer le programme tant que ces instructions ne sont pas terminées. Cela concerne donc particulièrement les applications du Web.
La programmation asynchrone permet de gérer un ensemble d’événements de façon concurrente.
L'idée générale de la programmation asynchrone est de pouvoir démarrer des opérations non bloquantes de façon concurrente, puis de pouvoir suivre leurs états et finalement exécuter des fonctions de retour (callbacks) quand elles sont prêtes.
Pour cela le programme va gérer une boucle qui attend que des événements (event loop) se produisent et alors fait correspondre à chaque événement qui survient la fonction qui lui est associée. C'est dans la fonction associée que sont définis les traitement à faire.
Exemple pour un serveur Web :
Précisions :
La bibliothèque asyncio permet de faire de la programmation asynchrone et dispose de deux éléments fondamentaux, une event loop et la classe Future.
La mise en oeuvre de la programmation asynchrone avec la bibliothèque asyncio nécessite l'utilisation deux mots clés async et await :
Première possibilité pour créer une boucle d'événement (event loop) :
import asyncio import time # Definir une coroutine qui sera exécutée ultérieurement (dans le futur) async def maCoroutine(): print("Début de ma Coroutine") time.sleep(2) print("Fin de ma Coroutine") # Faire tourner une simple boucle d'événement # jusqu'à ce que l'exécution a la coroutine soit finie (completed) loop = asyncio.get_event_loop() loop.run_until_complete(maCoroutine()) # fermer la boucle d'événement print("fermer la boucle d'événement") loop.close()
Pour exécuter la boucle d'événement on peut :
La méthode run_forever() permet à la boucle d'événement de s'exécuter indéfiniment jusqu'à ce que le programme se termine ou si la méthode stop() est appelée. La méthode ensure_future() permet également de déclarer une coroutine et sera utile pour déclarer plusieurs coroutines dans la même boucle d'événement.
import asyncio async def maCoroutine(): while True: print("Début de ma Coroutine") await asyncio.sleep(1) print("Fin de ma Coroutine") loop = asyncio.get_event_loop() try: asyncio.ensure_future(maCoroutine()) loop.run_forever() except KeyboardInterrupt: pass finally: # fermer la boucle d'événement print("fermer la boucle d'événement") loop.close()
Précisions :
La fonction utilise une boucle infinie et donc le programme va boucler indéfiniment. Il est possible alors
:
Un intérête de la programmation asynchrone est de pourvoir gérer des tâches en parallèle :
import asyncio async def tache_1(): while True: print("Début de ma tâche 1") await asyncio.sleep(1) print("Fin de ma tâche 1") async def tache_2(): while True: print("Début de ma tâche 2") await asyncio.sleep(5) print("Fin de ma tâche 2") loop = asyncio.get_event_loop() try: asyncio.ensure_future(tache_1()) asyncio.ensure_future(tache_2()) loop.run_forever() except KeyboardInterrupt: pass finally: # fermer la boucle d'événement print("Fermer la boucle d'événement") loop.close()
Voici le résultat obtenu :
>>> RESTART: D:/Developpement/python/Websocket/scripts/coroutine_future_parallele.py Début de ma tâche 1 Début de ma tâche 2 Fin de ma tâche 1 Début de ma tâche 1 Fin de ma tâche 1 Début de ma tâche 1 Fin de ma tâche 1 Début de ma tâche 1 Fin de ma tâche 1 Début de ma tâche 1 Fin de ma tâche 2 Début de ma tâche 2 Fin de ma tâche 1 Début de ma tâche 1 Fin de ma tâche 1 Début de ma tâche 1 Fermer la boucle d'événement >>>
La tâche 1 s'exécute plus souvent que la tâche 2. Ces deux tâches s'exécutent indépendamment l'une de l'autre.