Politiques
**********

Une politique de boucle d'événements est un objet global utilisé pour
obtenir et définir la boucle d'événements actuelle, ainsi que créer de
nouvelles boucles d'événements. La politique par défaut peut être
remplacée par des alternatives intégrées afin d'utiliser d'autres
implémentations de boucles d'événements, ou remplacée par une
politique personnalisée qui peut remplacer ces comportements.

Un objet politique définit la notion de *contexte* et gère une boucle
d'événement distincte par contexte. Ceci est valable fil par fil
d'exécution par défaut, bien que les politiques personnalisées
puissent définir le *contexte* différemment.

En utilisant une politique de boucle d'événement personnalisée, le
comportement des fonctions "get_event_loop()", "set_event_loop()" et
"new_event_loop()" peut être personnalisé.

Les objets politiques doivent implémenter les API définies dans la
classe mère abstraite "AbstractEventLoopPolicy".


Obtenir et définir la politique
===============================

Les fonctions suivantes peuvent être utilisées pour obtenir et définir
la politique du processus en cours :

asyncio.get_event_loop_policy()

   Renvoie la politique actuelle à l'échelle du processus.

asyncio.set_event_loop_policy(policy)

   Définit la politique actuelle sur l'ensemble du processus sur
   *policy*.

   Si *policy* est définie sur "None", la politique par défaut est
   restaurée.


Objets politiques
=================

La classe mère abstraite de la politique de boucle d'événements est
définie comme suit :

class asyncio.AbstractEventLoopPolicy

   Une classe de base abstraite pour les politiques *asyncio*.

   get_event_loop()

      Récupère la boucle d'évènements pour le contexte actuel.

      Renvoie un objet de boucle d'événements en implémentant
      l'interface "AbstractEventLoop".

      Cette méthode ne devrait jamais renvoyer "None".

      Modifié dans la version 3.6.

   set_event_loop(loop)

      Définit la boucle d'événements du contexte actuel sur *loop*.

   new_event_loop()

      Crée et renvoie un nouvel objet de boucle d'événements.

      Cette méthode ne devrait jamais renvoyer "None".

   get_child_watcher()

      Récupère un objet observateur du processus enfant.

      Renvoie un objet observateur implémentant l'interface
      "AbstractChildWatcher".

      Cette fonction est spécifique à Unix.

   set_child_watcher(watcher)

      Définit l'observateur du processus enfant actuel à *watcher*.

      Cette fonction est spécifique à Unix.

*asyncio* est livré avec les politiques intégrées suivantes :

class asyncio.DefaultEventLoopPolicy

   La politique *asyncio* par défaut. Utilise "SelectorEventLoop" sur
   les plates-formes Unix et "ProactorEventLoop" sur Windows.

   Il n'est pas nécessaire d'installer la politique par défaut
   manuellement. *asyncio* est configuré pour utiliser automatiquement
   la politique par défaut.

   Modifié dans la version 3.8: Sous Windows, "ProactorEventLoop" est
   désormais utilisée par défaut.

   Note:

     In Python versions 3.10.9, 3.11.1 and 3.12 the "get_event_loop()"
     method of the default asyncio policy emits a "DeprecationWarning"
     if there is no running event loop and no current loop is set. In
     some future Python release this will become an error.

class asyncio.WindowsSelectorEventLoopPolicy

   Politique de boucle d'événements alternative utilisant
   l'implémentation de la boucle d'événements "ProactorEventLoop".

   Disponibilité : Windows.

class asyncio.WindowsProactorEventLoopPolicy

   Politique de boucle d'événements alternative utilisant
   l'implémentation de la boucle d'événements "ProactorEventLoop".

   Disponibilité : Windows.


Observateurs de processus
=========================

Un observateur de processus permet de personnaliser la manière dont
une boucle d'événements surveille les processus enfants sous Unix.
Plus précisément, la boucle d'événements a besoin de savoir quand un
processus enfant s'est terminé.

Dans *asyncio*, les processus enfants sont créés avec les fonctions
"create_subprocess_exec()" et "loop.subprocess_exec()".

*asyncio* définit la classe mère abstraite "AbstractChildWatcher", que
les observateurs enfants doivent implémenter et possède quatre
implémentations différentes : "ThreadedChildWatcher" (configurée pour
être utilisé par défaut), "MultiLoopChildWatcher", "SafeChildWatcher"
et "FastChildWatcher".

Voir aussi la section sous-processus et fils d'exécution.

Les deux fonctions suivantes peuvent être utilisées pour personnaliser
l'implémentation de l'observateur de processus enfant utilisé par la
boucle d'événements *asyncio* :

asyncio.get_child_watcher()

   Renvoie l'observateur enfant actuel pour la politique actuelle.

asyncio.set_child_watcher(watcher)

   Définit l'observateur enfant actuel à *watcher* pour la politique
   actuelle. *watcher* doit implémenter les méthodes définies dans la
   classe de base "AbstractChildWatcher".

Note:

  Les implémentations de boucles d'événements tierces peuvent ne pas
  prendre en charge les observateurs enfants personnalisés. Pour ces
  boucles d'événements, utiliser "set_child_watcher()" pourrait être
  interdit ou n'avoir aucun effet.

class asyncio.AbstractChildWatcher

   add_child_handler(pid, callback, *args)

      Enregistre un nouveau gestionnaire.

      Organise l'appel de "callback(pid, returncode, * args)"
      lorsqu'un processus dont le *PID* est égal à *pid* se termine.
      La spécification d'un autre rappel pour le même processus
      remplace le gestionnaire précédent.

      L'appelable *callback* doit être compatible avec les programmes
      à fils d'exécution multiples.

   remove_child_handler(pid)

      Supprime le gestionnaire de processus avec un PID égal à *pid*.

      La fonction renvoie "True" si le gestionnaire a été supprimé
      avec succès, "False" s'il n'y a rien à supprimer.

   attach_loop(loop)

      Attache l'observateur à une boucle d'événement.

      Si l'observateur était précédemment attaché à une boucle
      d'événements, il est d'abord détaché avant d'être rattaché à la
      nouvelle boucle.

      Remarque : la boucle peut être "None".

   is_active()

      Renvoie "True" si l'observateur est prêt à être utilisé.

      La création d'un sous-processus avec un observateur enfant
      actuel *inactif* lève une "RuntimeError".

      Nouveau dans la version 3.8.

   close()

      Ferme l'observateur.

      Cette méthode doit être appelée pour s'assurer que les
      ressources sous-jacentes sont nettoyées.

class asyncio.ThreadedChildWatcher

   Cette implémentation démarre un nouveau fil d'exécution en attente
   pour chaque génération de sous-processus.

   Il fonctionne de manière fiable même lorsque la boucle d'événements
   *asyncio* est exécutée dans un fil d'exécution non principal.

   There is no noticeable overhead when handling a big number of
   children (*O*(1) each time a child terminates), but starting a
   thread per process requires extra memory.

   Cet observateur est utilisé par défaut.

   Nouveau dans la version 3.8.

class asyncio.MultiLoopChildWatcher

   Cette implémentation enregistre un gestionnaire de signal "SIGCHLD"
   lors de l'instanciation. Cela peut casser le code tiers qui
   installe un gestionnaire personnalisé pour le signal "SIGCHLD".

   L'observateur évite de perturber un autre code qui crée des
   processus en interrogeant explicitement chaque processus sur un
   signal "SIGCHLD".

   Il n'y a aucune limitation pour l'exécution de sous-processus à
   partir de différents fils d'exécution une fois l'observateur
   installé.

   The solution is safe but it has a significant overhead when
   handling a big number of processes (*O*(*n*) each time a "SIGCHLD"
   is received).

   Nouveau dans la version 3.8.

class asyncio.SafeChildWatcher

   Cette implémentation utilise une boucle d'événements active du fil
   d'exécution principal pour gérer le signal "SIGCHLD". Si le fil
   d'exécution principal n'a pas de boucle d'événements en cours
   d'exécution, un autre fil ne pourra pas générer de sous-processus
   (une "RuntimeError" est levée).

   L'observateur évite de perturber un autre code qui crée des
   processus en interrogeant explicitement chaque processus sur un
   signal "SIGCHLD".

   This solution is as safe as "MultiLoopChildWatcher" and has the
   same *O*(*n*) complexity but requires a running event loop in the
   main thread to work.

class asyncio.FastChildWatcher

   Cette implémentation récupère tous les processus terminés en
   appelant directement "os.waitpid(-1)", cassant éventuellement un
   autre code qui génère des processus et attend leur fin.

   There is no noticeable overhead when handling a big number of
   children (*O*(1) each time a child terminates).

   Cette solution nécessite une boucle d'événements en cours
   d'exécution dans le fil d'exécution principal pour fonctionner,
   comme "SafeChildWatcher".

class asyncio.PidfdChildWatcher

   Cette implémentation interroge les descripteurs de fichiers de
   processus (*pidfds*) pour attendre la fin du processus enfant. À
   certains égards, "PidfdChildWatcher" est une implémentation
   d'observateur d'enfants *Goldilocks*. Elle ne nécessite ni signaux
   ni threads, n'interfère avec aucun processus lancé en dehors de la
   boucle d'événements et évolue de manière linéaire avec le nombre de
   sous-processus lancés par la boucle d'événements. Le principal
   inconvénient est que les *pidfds* sont spécifiques à Linux et ne
   fonctionnent que sur les noyaux récents (5.3+).

   Nouveau dans la version 3.9.


Politiques personnalisées
=========================

Pour implémenter une nouvelle politique de boucle d’événements, il est
recommandé de sous-classer "DefaultEventLoopPolicy" et de
réimplémenter les méthodes pour lesquelles un comportement
personnalisé est souhaité, par exemple :

   class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):

       def get_event_loop(self):
           """Get the event loop.

           This may be None or an instance of EventLoop.
           """
           loop = super().get_event_loop()
           # Do something with loop ...
           return loop

   asyncio.set_event_loop_policy(MyEventLoopPolicy())
