8.3. La boucle d’événements¶
La boucle d’événements est le moteur qu’asyncio exécute en arrière-plan. Elle tient à jour une liste de chaque tâche du programme, demande à chacune de s’exécuter jusqu’à son prochain await, puis passe à la tâche prête suivante. Lorsqu’aucune tâche n’est prête, elle attend — cette attente effective est ce qui rend le CPU disponible pour que le micrologiciel exécute d’autres choses et pour que les mises en veille économes en énergie s’enclenchent — jusqu’à ce que quelque chose qu’une tâche attendait devienne disponible, puis elle reprend cette tâche. À répéter indéfiniment.
La plupart des applications n’interagissent jamais directement avec la boucle. La boucle est une conséquence de l’appel à asyncio.run() ; l’application écrit des coroutines, les ordonnance comme tâches, et la boucle fait le reste.
8.3.1. Ce que fait réellement asyncio.run()¶
Un unique appel:
asyncio.run(main())
est un raccourci pour une séquence plus longue que la boucle gère pour le compte de l’application :
Créer la boucle d’événements si elle n’existe pas déjà.
Encapsuler la coroutine fournie dans une tâche et l’ordonnancer comme point d’entrée de premier niveau de la boucle.
Exécuter la boucle — parcourir les tâches prêtes, attendre quand aucune n’est prête, reprendre les tâches lorsque leurs awaits s’achèvent — jusqu’à ce que la tâche de premier niveau retourne ou lève une exception.
Annuler toutes les tâches créées par l’application qui sont encore en cours d’exécution.
Renvoyer ce que la coroutine de premier niveau a renvoyé (ou relever à nouveau ce qu’elle a levé).
8.3.2. Une seule boucle par programme¶
L’asyncio de MicroPython a une seule boucle d’événements, point final. On ne crée pas de nouvelle boucle, et on n’imbrique pas une boucle dans une autre. Appeler asyncio.run() depuis l’intérieur d’une coroutine qui s’exécute déjà sur la boucle est une erreur ; la boucle est déjà là, et la coroutine n’a qu’à attendre (await) ce qu’elle voulait démarrer.
En pratique, la règle est la même que la phrase de clôture de la page précédente : il y a exactement un appel à asyncio.run() par programme, en tête, avec une unique async def main() derrière. Tout le reste vit à l’intérieur de main.
8.3.3. Accès direct à la boucle¶
Pour les rares cas où une application doit toucher la boucle elle-même — principalement les diagnostics et les gestionnaires d’exceptions — asyncio.get_event_loop() renvoie l’objet Loop. À partir de là, l’application peut installer un gestionnaire d’exceptions personnalisé, inspecter ce que fait la boucle, ou (très occasionnellement) appeler directement create_task() au lieu de asyncio.create_task() (il s’agit de la même opération).
L’ensemble complet des méthodes exposées par Loop — run_forever(), stop(), set_exception_handler(), et les autres — est traité dans la page contrôle de la boucle plus loin dans cette section. D’ici là, asyncio.run(main()) est tout ce dont une application a besoin.