Políticas
*********

Una política del bucle de eventos es un objeto por proceso que
controla la administración del bucle de eventos. Cada bucle de eventos
tiene una política por defecto, que puede ser cambiada y editada
usando la política de API.

Una política define la noción de *contexto* y administra un bucle de
eventos separado por contexto. La política por defecto define un
*contexto* como el estado actual.

Usando una política de bucle de eventos personalizada, la conducta de
las funciones "get_event_loop()", "set_event_loop()", y
"new_event_loop()" puede ser personalizada.

Los objetos de política deberían implementar las APIs definidas en la
clase abstracta base "AbstractEventLoopPolicy".


Obteniendo y Configurando la Política
=====================================

Las siguientes funciones pueden ser usadas para obtener y configurar
la política de los procesos actuales:

asyncio.get_event_loop_policy()

   Retorna la política actual en todo el proceso.

asyncio.set_event_loop_policy(policy)

   Establece la política actual en todo el proceso a *policy*.

   Si *policy* está configurado a "None", la política por defecto se
   reestablece.


Objetos de Política
===================

La clase base de política de bucle de eventos abstractos se define de
la siguiente manera:

class asyncio.AbstractEventLoopPolicy

   Una clase base abstracta para políticas asyncio.

   get_event_loop()

      Retorna el bucle de eventos para el contexto actual.

      Retorna un objeto bucle de eventos implementando la interfaz
      "AbstractEventLoop".

      Este método nunca debería retornar "None".

      Distinto en la versión 3.6.

   set_event_loop(loop)

      Establece el bucle de eventos para el contexto a *loop*.

   new_event_loop()

      Crea y retorna un nuevo objeto de bucle de eventos.

      Este método nunca debería retornar "None".

   get_child_watcher()

      Retorna un objeto observador de procesos secundarios.

      Retorna un objeto observador implementando la interfaz
      "AbstractChildWatcher".

      Esta función es específica de Unix.

   set_child_watcher(watcher)

      Establece el observador de procesos secundarios actuales a
      *watcher*.

      Esta función es específica de Unix.

asyncio se envía con las siguientes políticas integradas:

class asyncio.DefaultEventLoopPolicy

   La política por defecto asyncio.  Usa "SelectorEventLoop" en Unix y
   "ProactorEventLoop" en Windows.

   No hay necesidad de instalar la política por defecto manualmente.
   asyncio está configurado para usar la política por defecto
   automáticamente.

   Distinto en la versión 3.8: En Windows, "ProactorEventLoop" ahora
   se usa por defecto.

class asyncio.WindowsSelectorEventLoopPolicy

   Una política de bucle de eventos alternativa que usa la
   implementación de bucle de eventos "SelectorEventLoop".

   Disponibilidad: Windows.

class asyncio.WindowsProactorEventLoopPolicy

   Una política de bucle de eventos alternativa que usa la
   implementación de bucle de eventos "ProactorEventLoop".

   Disponibilidad: Windows.


Observadores de procesos
========================

Un observador de procesos permite personalizar cómo un bucle de
eventos monitorea procesos secundarios en Unix. Específicamente, un
bucle de eventos necesita saber cuándo un proceso secundario ha
terminado.

En asyncio, los procesos secundarios son creados con las funciones
"créate_subprocess_exec()" y "loop.subprocess_exec()".

asyncio define la clase base abstracta "AbstractChildWatcher", qué
observadores de subprocesos deberían implementarse, y tiene cuatro
implementaciones diferentes: "ThreadedChildWatcher" (configurado para
ser usado por defecto), "MultiLoopChildWatcher", "SaferChildWatcher",
y "FastChildWatcher".

Mirar también la sección Subprocesos e hilos.

Las siguientes dos funciones pueden ser usadas para personalizar la
implementación de observadores de procesos secundarios usados por el
bucle de eventos de asyncio:

asyncio.get_child_watcher()

   Retorna el observador de procesos secundarios para la política
   actual.

asyncio.set_child_watcher(watcher)

   Establece el observador de procesos secundarios actuales a
   *watcher* para la política actual. *watcher* debe implementar
   métodos definidos en la clase base "AbstractChildWatcher".

Nota:

  Implementaciones de bucles de eventos de terceras partes no deben
  dar soporte a observadores de procesos secundarios personalizados.
  Para dichos bucles de eventos, usando "set_child_watcher()" podría
  estar prohibido o no tener efecto.

class asyncio.AbstractChildWatcher

   add_child_handler(pid, callback, *args)

      Registra un nuevo gestor de proceso secundario.

      Arreglo para "callback(pid, returncode, *args)" a ser invocado
      cuando un proceso con PID igual a *pid* termina. Especificando
      otro retrollamada para el mismo proceso reemplaza el gestor
      previo.

      El *callback* invocable debe ser seguro para hilos.

   remove_child_handler(pid)

      Remueve el gestor para el proceso con PID igual a *pid*.

      La función retorna "True" si el gestor fue removido de forma
      exitosa, "False" si no hubo nada que remover.

   attach_loop(loop)

      Adjunta el observador a un bucle de eventos.

      Si el observador estaba previamente adjuntado a un bucle de
      eventos, entonces primero es separado antes de adjuntar el nuevo
      bucle.

      Nota: el bucle puede ser "None".

   is_active()

      Retorna "True" si el observador está listo para usarse.

      Generar un nuevo subproceso con observador de procesos
      secundarios actual *inactive* lanza "RuntimeError".

      Nuevo en la versión 3.8.

   close()

      Cierra el observador.

      Este método tiene que ser invocado para asegurar que los objetos
      subyacentes están limpiados.

class asyncio.ThreadedChildWatcher

   Esta implementación inicia un nuevo hilo esperando para cada
   subproceso generado.

   Trabaja de manera confiable incluso cuando el bucle de eventos
   asyncio se ejecuta en un hilo de SO no principal.

   No hay sobrecarga notable cuando se gestiona un número grande de
   procesos secundarios (*O(1)* cada vez que un proceso secundario
   termina), pero iniciar un hilo por proceso requiere memoria extra.

   Este observador es usado por defecto.

   Nuevo en la versión 3.8.

class asyncio.MultiLoopChildWatcher

   Esta implementación registra un gestor de señal en instanciación
   "SIGCHLD". Eso puede romper código de terceras partes que instalen
   un gestor personalizado para la señal "SIGCHLD".

   El observador evita interrumpir otro código generando procesos
   sondeando cada proceso explícitamente en una señal "SIGCHLD".

   No hay limitación para ejecutar subprocesos de diferentes hilos una
   vez el observador es instalado.

   La solución es segura pero tiene una sobrecarga significativa
   cuando se gestiona un número grande de procesos (*O(n)* cada vez
   que un "SIGCHLD" es recibido).

   Nuevo en la versión 3.8.

class asyncio.SafeChildWatcher

   Esta implementación usa bucles de eventos activos del hilo
   principal para gestionar la señal "SIGCHLD". Si el hilo principal
   no tiene bucles de eventos en ejecución otro hilo no puede generar
   un subproceso ("RuntimeError" es disparada).

   El observador evita interrumpir otro código generando procesos
   sondeando cada proceso explícitamente en una señal "SIGCHLD".

   Esta solución es tan segura como "MultiLoopChildWatcher" y tiene la
   misma complejidad *O(n)* pero requiere de un bucle de eventos
   ejecutándose en el hilo principal para trabajar.

class asyncio.FastChildWatcher

   Esta implementación cosecha cada proceso terminado llamando
   "os.waitpad(-1)" directamente, posiblemente rompiendo otro código
   generando procesos y esperando por su terminación.

   No hay sobrecarga notable cuando se gestiona un número grande de
   procesos secundarios (*O(1)* cada vez que un proceso secundario
   termina).

   Esta solución requiere un bucle de eventos ejecutándose en el hilo
   principal para trabajar, como "SafeChildWatcher".

class asyncio.PidfdChildWatcher

   Esta implementación sondea los descriptores de archivos de proceso
   (pidfds) para esperar la terminación del proceso hijo. En ciertos
   sentidos "PidfdChildWatcher" es una implementación de niño
   vigilante "Ricitos de oro". No requiere señales o hilos, no
   interfiere con ningún proceso lanzado fuera del bucle de eventos y
   escala linealmente con el número de subprocesos lanzados por el
   bucle de eventos. La principal desventaja es que los pidfds son
   específicos de Linux y solo funcionan en kernels recientes (5.3+).

   Nuevo en la versión 3.9.


Personalizar Políticas
======================

Para implementar una nueva política de bucle de eventos, se recomienda
heredar "DefaultEventLoopPolicy" y sobreescribir los métodos para los
cuales se desea una conducta personalizada, por ejemplo:

   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())
