select — ожидание событий на наборе потоков

Этот модуль предоставляет функции для эффективного ожидания того, что один или несколько потоков (файлоподобных объектов, реализующих потоковый протокол, таких как сокеты, UART и другие объекты ввода-вывода) готовы к чтению или записи, вместо активного ожидания или блокировки на одном объекте.

Объект poll — рекомендуемый интерфейс: он масштабируется на множество потоков и не выполняет выделения памяти при использовании через poll.ipoll(). Функция уровня модуля select() — менее эффективный интерфейс для совместимости.

Пример использования объекта 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())

Пример использования функции уровня модуля select():

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)

Функции

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

Ожидает, пока один или несколько заданных потоковых объектов не будут готовы, или пока не истечёт timeout.

  • rlist — список объектов для отслеживания готовности к чтению.

  • wlist — список объектов для отслеживания готовности к записи.

  • xlist — список объектов для отслеживания состояния ошибки или разрыва соединения.

  • timeout — максимальное время ожидания в секундах (допускается значение с плавающей точкой). Если оно опущено или равно None, вызов блокируется бесконечно; 0 возвращает управление немедленно (неблокирующий опрос).

Возвращает кортеж из трёх списков (rlist, wlist, xlist). Каждый возвращаемый список — это подмножество соответствующего входного списка, содержащее объекты, которые стали готовы к чтению, готовы к записи или сообщили об ошибке/разрыве соединения соответственно. Если timeout истекает и ничего не готово, все три списка пусты.

Эта функция менее эффективна, чем poll (она перестраивает свой внутренний набор опроса при каждом вызове); по возможности используйте poll.

Константы

select.POLLIN: int

Имеются данные, доступные для чтения из потока.

select.POLLOUT: int

Поток может принять больше данных для записи.

select.POLLERR: int

В потоке возникло состояние ошибки. Это незапрошенное событие: оно сообщается poll.poll() / poll.ipoll(), даже если оно не запрашивалось в eventmask, и его недопустимо передавать как входное значение eventmask.

select.POLLHUP: int

Поток был разорван / отключён. Это незапрошенное событие: оно сообщается poll.poll() / poll.ipoll(), даже если оно не запрашивалось в eventmask, и его недопустимо передавать как входное значение eventmask.

Классы

class select.poll

Создаёт объект опроса, который поддерживает набор зарегистрированных потоков (или любых объектов, реализующих потоковый протокол) и эффективно ожидает, пока один или несколько из них не станут доступны для чтения, записи или не сообщат об исключительном состоянии.

Потоки добавляются с помощью register(), удаляются с помощью unregister(), а набор отслеживаемых событий можно изменить с помощью modify(). После настройки вызовите poll(), чтобы заблокироваться до готовности чего-либо (или истечения тайм-аута), либо ipoll() для варианта на основе итератора без выделения памяти.

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

Регистрирует поток obj для опроса, отслеживая события, заданные eventmask (логическое ИЛИ из):

  • select.POLLIN – доступны данные для чтения

  • select.POLLOUT – поток может принять больше данных для записи

eventmask по умолчанию равен select.POLLIN | select.POLLOUT.

select.POLLHUP и select.POLLERR недопустимы во входном eventmask — это незапрошенные события, которые сообщаются poll() / ipoll() независимо от того, запрашивались ли они (это соответствует семантике POSIX).

Допустимо вызывать этот метод более одного раза для одного и того же obj: последующий вызов обновляет маску событий obj, действуя как modify().

unregister(obj: Any) None

Удаляет obj из набора зарегистрированных потоков. Отмена регистрации obj, который в данный момент не зарегистрирован, не является ошибкой (в этом случае вызов не имеет эффекта).

modify(obj: Any, eventmask: int) None

Изменяет маску событий для уже зарегистрированного obj на eventmask. Возбуждает OSError с errno.ENOENT, если obj не зарегистрирован.

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

Блокируется до тех пор, пока хотя бы один зарегистрированный поток не станет готовым или не сообщит об исключительном состоянии, затем возвращает список потоков, которые сработали.

timeout — максимальное время ожидания в миллисекундах. Если оно опущено или равно -1, вызов блокируется бесконечно; 0 возвращает управление немедленно (неблокирующий опрос).

Возвращает список кортежей (obj, event, ...), по одному на каждый сработавший поток. obj — зарегистрированный поток, а event — побитовое ИЛИ возникших флагов select.POLLIN / select.POLLOUT / select.POLLERR / select.POLLHUP. Каждый кортеж может содержать дополнительные элементы, определяемые реализацией, поэтому не следует предполагать, что его длина равна ровно 2. Если timeout истекает и ничего не готово, возвращается пустой список.

select.POLLHUP и select.POLLERR могут быть возвращены в любое время (даже если они не запрашивались) и на них необходимо реагировать — как правило, отменяя регистрацию и закрывая затронутый поток — иначе последующие вызовы будут продолжать немедленно возвращаться с установленными этими флагами для данного потока.

Гарантируется, что все ожидающие запланированные функции обратного вызова будут выполнены до входа в цикл опроса.

Отличие от CPython

Возвращаемые кортежи могут содержать более 2 элементов, как описано выше.

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

Аналогично poll(), но вместо построения списка возвращает итератор, который выдаёт по одному кортежу (obj, event, ...) за раз. Это позволяет избежать выделения памяти при каждом вызове, что важно для планировщиков асинхронного ввода-вывода.

Выдаваемый кортеж принадлежит вызываемой стороне: он повторно используется (перезаписывается) на следующей итерации, поэтому его содержимое должно быть использовано в теле цикла, а ссылки на него не должны сохраняться.

timeout имеет то же значение, что и для poll(). Если flags равен 1, используется одноразовое поведение: у потока, событие которого сработало, маска событий автоматически очищается (эквивалентно poll.modify(obj, 0)), поэтому никакие дальнейшие события для него не сообщаются, пока его маска не будет снова установлена с помощью modify().

Гарантируется, что все ожидающие запланированные функции обратного вызова будут выполнены до входа в цикл опроса.

Отличие от CPython

Этот метод является расширением MicroPython.