selectors — 高级 I/O 多路复用

3.4 版新增。

源代码: Lib/selectors.py


简介

此模块允许进行高级且高效的 I/O 多路复用,它构建在 select 模块原语之上。鼓励用户使用此模块,除非他们想要精确控制所使用的操作系统级原语。

它定义了一个 BaseSelector 抽象基类,以及几个具体实现(KqueueSelectorEpollSelector 等),可用于等待多个文件对象上的 I/O 就绪通知。在下文中,“文件对象”指的是任何具有 fileno() 方法的对象,或原始文件描述符。请参阅 文件对象

DefaultSelector 是当前平台上可用的最高效实现的别名:这应该是大多数用户的默认选择。

注意

支持的文件对象类型取决于平台:在 Windows 上,支持套接字,但不支持管道,而在 Unix 上,两者都支持(也可能支持其他一些类型,例如 fifo 或特殊文件设备)。

参见

select

低级 I/O 多路复用模块。

可用性:不支持 Emscripten,不支持 WASI。

此模块在 WebAssembly 平台 wasm32-emscriptenwasm32-wasi 上不可用或无法工作。有关更多信息,请参阅 WebAssembly 平台

类层次结构

BaseSelector
+-- SelectSelector
+-- PollSelector
+-- EpollSelector
+-- DevpollSelector
+-- KqueueSelector

在下文中,*events* 是一个位掩码,指示应在给定文件对象上等待哪些 I/O 事件。它可以是以下模块常量的组合

常量

含义

selectors.EVENT_READ

可读取

selectors.EVENT_WRITE

可写入

class selectors.SelectorKey

SelectorKey 是一个 namedtuple,用于将文件对象与其底层文件描述符、选定的事件掩码和附加数据相关联。它由多个 BaseSelector 方法返回。

fileobj

已注册的文件对象。

fd

底层文件描述符。

events

必须在此文件对象上等待的事件。

data

与此文件对象关联的不透明数据(可选):例如,这可用于存储每个客户端的会话 ID。

class selectors.BaseSelector

BaseSelector 用于等待多个文件对象上的 I/O 事件就绪。它支持文件流注册、取消注册以及一种方法,该方法用于等待这些流上的 I/O 事件,并带有一个可选的超时时间。它是一个抽象基类,因此不能实例化。请改用 DefaultSelector,或者如果要专门使用某个实现并且您的平台支持它,则使用 SelectSelectorKqueueSelector 等。BaseSelector 及其具体实现支持 上下文管理器 协议。

abstractmethod register(fileobj, events, data=None)

注册一个文件对象以进行选择,监视其 I/O 事件。

*fileobj* 是要监视的文件对象。它可以是整数文件描述符,也可以是具有 fileno() 方法的对象。*events* 是要监视的事件的位掩码。*data* 是一个不透明对象。

这将返回一个新的 SelectorKey 实例,如果事件掩码或文件描述符无效,则会引发 ValueError,如果文件对象已注册,则会引发 KeyError

abstractmethod unregister(fileobj)

取消注册文件对象以进行选择,将其从监视中移除。文件对象在关闭之前应先取消注册。

*fileobj* 必须是先前注册的文件对象。

这将返回关联的 SelectorKey 实例,如果 *fileobj* 未注册,则会引发 KeyError。如果 *fileobj* 无效(例如,它没有 fileno() 方法或其 fileno() 方法的返回值无效),则会引发 ValueError

modify(fileobj, events, data=None)

更改已注册文件对象的监视事件或附加数据。

这等效于先执行 BaseSelector.unregister(fileobj),再执行 BaseSelector.register(fileobj, events, data),但可以更高效地实现。

这将返回一个新的 SelectorKey 实例,如果事件掩码或文件描述符无效,则引发 ValueError,如果文件对象未注册,则引发 KeyError

abstractmethod select(timeout=None)

等待某些已注册的文件对象变为就绪状态,或超时。

如果 timeout > 0,则指定最大等待时间(以秒为单位)。如果 timeout <= 0,则调用不会阻塞,并将报告当前就绪的文件对象。如果 *timeout* 为 None,则调用将阻塞,直到某个受监视的文件对象变为就绪状态。

这将返回一个 (key, events) 元组列表,每个就绪文件对象对应一个元组。

key 是与就绪文件对象对应的 SelectorKey 实例。events 是此文件对象上就绪事件的位掩码。

注意

如果当前进程接收到信号,则此方法可能会在任何文件对象变为就绪状态或超时之前返回:在这种情况下,将返回一个空列表。

在 3.5 版更改: 如果信号处理程序没有引发异常,则当选择器被信号中断时,现在将使用重新计算的超时时间重试选择器(有关基本原理,请参阅 PEP 475),而不是在超时之前返回一个空的事件列表。

close()

关闭选择器。

必须调用此方法以确保释放任何底层资源。选择器一旦关闭,就不应再使用。

get_key(fileobj)

返回与已注册文件对象关联的键。

这将返回与此文件对象关联的 SelectorKey 实例,如果文件对象未注册,则引发 KeyError

abstractmethod get_map()

返回文件对象到选择器键的映射。

这将返回一个 Mapping 实例,该实例将已注册的文件对象映射到与其关联的 SelectorKey 实例。

class selectors.DefaultSelector

默认选择器类,使用当前平台上可用的最高效实现。这应该是大多数用户的默认选择。

class selectors.SelectSelector

基于 select.select() 的选择器。

class selectors.PollSelector

基于 select.poll() 的选择器。

class selectors.EpollSelector

基于 select.epoll() 的选择器。

fileno()

这将返回底层 select.epoll() 对象使用的文件描述符。

class selectors.DevpollSelector

基于 select.devpoll() 的选择器。

fileno()

这将返回底层 select.devpoll() 对象使用的文件描述符。

3.5 版新增。

class selectors.KqueueSelector

基于 select.kqueue() 的选择器。

fileno()

这将返回底层 select.kqueue() 对象使用的文件描述符。

示例

这是一个简单的回显服务器实现

import selectors
import socket

sel = selectors.DefaultSelector()

def accept(sock, mask):
    conn, addr = sock.accept()  # Should be ready
    print('accepted', conn, 'from', addr)
    conn.setblocking(False)
    sel.register(conn, selectors.EVENT_READ, read)

def read(conn, mask):
    data = conn.recv(1000)  # Should be ready
    if data:
        print('echoing', repr(data), 'to', conn)
        conn.send(data)  # Hope it won't block
    else:
        print('closing', conn)
        sel.unregister(conn)
        conn.close()

sock = socket.socket()
sock.bind(('localhost', 1234))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)

while True:
    events = sel.select()
    for key, mask in events:
        callback = key.data
        callback(key.fileobj, mask)