18.4.selectors — 高层 I/O 多路复用

3.4 版新加入。

源码︰Lib/selectors.py

18.4.1. 介绍

这个模块允许高层高效的 I/O 多路复用,建立在 选择 模块原函数基础之上。鼓励用户使用此模块,除非他们想精确控制系统级别原函数的使用。

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

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

注意

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

令请参阅

select
低层 I/O 多路复用模块。

18.4.2.

类层次结构︰

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

在下文中,事件 是指那些等待I/O 事件的给定的文件对象的位掩码。它可以是下面的模块常量的组合︰

Constant Meaning
EVENT_READ Available for read
EVENT_WRITE Available for 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 无效则抛出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()

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

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

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)