Skip to main content

18.4. selectors —高级I/O复用

3.4 新版功能.

源代码: Lib/selectors.py


18.4.1. 介绍

该模块允许基于 select 模块原语的高级和高效的I/O复用。鼓励用户使用此模块,除非他们需要精确控制所使用的操作系统级原语。

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

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

注解

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

参见

select

低级I/O复用模块。

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,或者使用 SelectSelectorKqueueSelector 等之一,并且您的平台支持它。 BaseSelector 及其具体实现支持 context manager 协议。

abstractmethod register(fileobj, events, data=None)

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

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

这返回一个新的 SelectorKey 实例,或者在无效事件掩码或文件描述符的情况下产生一个 ValueError,如果文件对象已经注册,则产生 KeyError

abstractmethod unregister(fileobj)

从选择中取消注册文件对象,将其从监视中删除。文件对象在关闭前应该取消注册。

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

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

modify(fileobj, events, data=None)

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

这相当于 BaseSelector.unregister(fileobj)() 随后是 BaseSelector.register(fileobj, events, data)(),除了它可以更有效地实现。

这将返回一个新的 SelectorKey 实例,或者在无效事件掩码或文件描述符的情况下产生一个 ValueError,如果文件对象未注册,则产生 KeyError

abstractmethod select(timeout=None)

等待直到某些已注册的文件对象准备就绪,或超时到期。

如果是 timeout > 0,则指定最大等待时间(以秒为单位)。如果是 timeout <= 0,调用不会阻塞,并且会报告当前准备好的文件对象。如果 timeoutNone,调用将阻塞,直到受监视的文件对象准备就绪。

这将返回一个 (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() 对象使用的文件描述符。

18.4.3. 例子

这里是一个简单的echo服务器实现:

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)