18.4. 选择器 — 高级 I/O 多路复用 — Python 文档
18.4. 选择器 — 高级 I/O 多路复用
3.4 版中的新功能。
源代码: :source:`Lib/selectors.py`
18.4.1. 介绍
该模块允许基于 select 模块原语的高级和高效 I/O 多路复用。 鼓励用户改用此模块,除非他们想要精确控制所使用的操作系统级原语。
它定义了一个 BaseSelector 抽象基类,以及几个具体实现(KqueueSelector、EpollSelector...),可用于等待 I/O 就绪通知在多个文件对象上。 在下文中,“文件对象”是指具有 fileno()
方法或原始文件描述符的任何对象。 请参阅 文件对象 。
DefaultSelector 是当前平台上可用的最有效实现的别名:这应该是大多数用户的默认选择。
笔记
支持的文件对象类型取决于平台:在 Windows 上,支持套接字,但不支持管道,而在 Unix 上,两者都支持(也可能支持其他一些类型,例如 fifos 或特殊文件设备)。
18.4.2. 班级
类层次结构:
BaseSelector
+-- SelectSelector
+-- PollSelector
+-- EpollSelector
+-- DevpollSelector
+-- KqueueSelector
在下面,events 是一个位掩码,指示应该在给定的文件对象上等待哪些 I/O 事件。 它可以是以下模块常量的组合:
持续的 意义 EVENT_READ
可供阅读 EVENT_WRITE
可写
- class selectors.SelectorKey
SelectorKey 是一个 namedtuple,用于将文件对象与其底层文件描述符、选定事件掩码和附加数据相关联。 它由几个 BaseSelector 方法返回。
- fileobj
已注册的文件对象。
- fd
底层文件描述符。
- events
必须在此文件对象上等待的事件。
- data
与此文件对象关联的可选不透明数据:例如,这可用于存储每个客户端的会话 ID。
- class selectors.BaseSelector
BaseSelector 用于等待多个文件对象上的 I/O 事件准备就绪。 它支持文件流注册、注销和等待这些流上的 I/O 事件的方法,具有可选的超时。 它是一个抽象基类,所以不能被实例化。 使用 DefaultSelector 或 SelectSelector、KqueueSelector 等之一。 如果您想专门使用一个实现,并且您的平台支持它。 BaseSelector及其具体实现支持context manager协议。
- modify(fileobj, events, data=None)
更改已注册文件对象的监视事件或附加数据。
这等价于
BaseSelector.unregister(fileobj)()
后跟BaseSelector.register(fileobj, events, data)()
,只是它可以更有效地实现。这将返回一个新的 SelectorKey 实例,或者在事件掩码或文件描述符无效的情况下引发 ValueError,如果文件对象未注册,则引发 KeyError。
- close()
关闭选择器。
必须调用它以确保释放任何底层资源。 选择器一旦关闭就不得使用。
- get_key(fileobj)
返回与注册文件对象关联的键。
这将返回与此文件对象关联的 SelectorKey 实例,或者如果文件对象未注册,则引发 KeyError。
- 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() 对象使用的文件描述符。
18.4.3. 例子
这是一个简单的回显服务器实现:
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)