select — esperar eventos en un conjunto de flujos

Este módulo proporciona funciones para esperar de forma eficiente hasta que uno o más flujos (objetos de tipo archivo que implementan el protocolo de flujo, como sockets, UART y otros objetos de E/S) estén listos para lectura o escritura, en lugar de hacer una espera activa o bloquearse en un solo objeto.

El objeto poll es la interfaz recomendada: escala a muchos flujos y no realiza asignaciones de memoria cuando se usa a través de poll.ipoll(). La función select() a nivel de módulo es una interfaz de compatibilidad menos eficiente.

Ejemplo usando un objeto poll:

import select

poller = select.poll()
poller.register(uart, select.POLLIN)

while True:
    # Wait up to 1000 ms for the UART to have data.
    for obj, event in poller.poll(1000):
        if event & select.POLLIN:
            print(obj.read())

Ejemplo usando la función select() a nivel de módulo:

import select

# Wait up to 1 second for the socket to become readable.
rlist, wlist, xlist = select.select([sock], [], [], 1.0)
if rlist:
    data = sock.recv(100)

Funciones

select.select(rlist: List, wlist: List, xlist: List, timeout: float | None = None) Tuple[List, List, List]

Espera hasta que uno o más de los objetos de flujo dados estén listos, o hasta que expire timeout.

  • rlist es una lista de objetos a monitorizar para comprobar su disponibilidad de lectura.

  • wlist es una lista de objetos a monitorizar para comprobar su disponibilidad de escritura.

  • xlist es una lista de objetos a monitorizar para detectar una condición de error o de desconexión.

  • timeout es el tiempo máximo de espera, en segundos (se acepta un valor de coma flotante). Si se omite o es None, la llamada se bloquea indefinidamente; 0 retorna de inmediato (un sondeo no bloqueante).

Devuelve una tupla de 3 listas (rlist, wlist, xlist). Cada lista devuelta es el subconjunto de la lista de entrada correspondiente que contiene los objetos que pasaron a estar listos para lectura, listos para escritura, o que señalaron un error/desconexión, respectivamente. Si transcurre timeout sin que nada esté listo, las tres listas están vacías.

Esta función es menos eficiente que poll (reconstruye su conjunto interno de sondeo en cada llamada); use poll en su lugar siempre que sea posible.

Constantes

select.POLLIN: int

Hay datos disponibles para leer del flujo.

select.POLLOUT: int

El flujo puede aceptar más datos para escribir.

select.POLLERR: int

Ocurrió una condición de error en el flujo. Este es un evento no solicitado: lo notifican poll.poll() / poll.ipoll() aunque no se haya solicitado en eventmask, y no es válido pasarlo como eventmask de entrada.

select.POLLHUP: int

El flujo se desconectó / cerró. Este es un evento no solicitado: lo notifican poll.poll() / poll.ipoll() aunque no se haya solicitado en eventmask, y no es válido pasarlo como eventmask de entrada.

Clases

class select.poll

Crea un objeto de sondeo que mantiene un conjunto de flujos registrados (o cualquier objeto que exponga el protocolo de flujo) y espera de forma eficiente hasta que uno o más de ellos pase a estar listo para lectura, escritura, o señale una condición excepcional.

Los flujos se añaden con register(), se eliminan con unregister(), y el conjunto de eventos a observar puede cambiarse con modify(). Una vez configurado, llame a poll() para bloquear hasta que algo esté listo (o transcurra un tiempo de espera), o a ipoll() para una variante basada en iterador sin asignación de memoria.

register(obj: Any, eventmask: int = select.POLLIN | select.POLLOUT) None

Registra el flujo obj para sondeo, observando los eventos indicados por eventmask (el OR lógico de):

eventmask tiene como valor predeterminado select.POLLIN | select.POLLOUT.

select.POLLHUP y select.POLLERR no son válidos en un eventmask de entrada: son eventos no solicitados que notifican poll() / ipoll() independientemente de si se solicitaron (esto coincide con la semántica de POSIX).

Está permitido llamar a este método más de una vez para el mismo obj: una llamada posterior actualiza la máscara de eventos de obj, comportándose como modify().

unregister(obj: Any) None

Elimina obj del conjunto de flujos registrados. No es un error dar de baja un obj que no está registrado actualmente (en ese caso la llamada no tiene ningún efecto).

modify(obj: Any, eventmask: int) None

Cambia la máscara de eventos de un obj ya registrado a eventmask. Genera OSError con errno.ENOENT si obj no está registrado.

poll(timeout: int = -1, /) List[Tuple]

Se bloquea hasta que al menos un flujo registrado pase a estar listo o señale una condición excepcional, y luego devuelve la lista de flujos que se activaron.

timeout es el tiempo máximo de espera en milisegundos. Si se omite o es -1, la llamada se bloquea indefinidamente; 0 retorna de inmediato (un sondeo no bloqueante).

Devuelve una lista de tuplas (obj, event, ...), una por cada flujo que se activó. obj es el flujo registrado y event es el OR a nivel de bits de las banderas select.POLLIN / select.POLLOUT / select.POLLERR / select.POLLHUP que ocurrieron. Cada tupla puede contener elementos adicionales definidos por la implementación, así que no asuma una longitud de exactamente 2. Si transcurre timeout sin que nada esté listo, se devuelve una lista vacía.

select.POLLHUP y select.POLLERR pueden devolverse en cualquier momento (incluso si no se solicitaron) y debe actuarse sobre ellos – normalmente dando de baja y cerrando el flujo afectado – de lo contrario, las llamadas posteriores seguirán retornando de inmediato con estas banderas activadas para ese flujo.

Se garantiza que todas las funciones de retorno (callbacks) programadas pendientes se ejecuten antes de entrar en el bucle de sondeo.

Diferencia con CPython

Las tuplas devueltas pueden contener más de 2 elementos, como se describe arriba.

ipoll(timeout: int = -1, flags: int = 0, /) Iterator[Tuple]

Como poll(), pero en lugar de construir una lista devuelve un iterador que produce una tupla (obj, event, ...) a la vez. Esto evita asignar memoria en cada llamada, lo cual es importante para los planificadores de E/S asíncrona.

La tupla producida es propiedad del invocado (callee): se reutiliza (se sobrescribe) en la siguiente iteración, por lo que su contenido debe consumirse dentro del cuerpo del bucle y no deben almacenarse referencias a ella.

timeout tiene el mismo significado que en poll(). Si flags es 1, se usa un comportamiento de un solo disparo (one-shot): un flujo cuyo evento se activó tiene su máscara de eventos borrada automáticamente (equivalente a poll.modify(obj, 0)), de modo que no se notifican más eventos para él hasta que su máscara se vuelva a establecer con modify().

Se garantiza que todas las funciones de retorno (callbacks) programadas pendientes se ejecuten antes de entrar en el bucle de sondeo.

Diferencia con CPython

Este método es una extensión de MicroPython.