18.4. 选择器 — 高级 I/O 多路复用 — Python 文档

来自菜鸟教程
Python/docs/3.6/library/selectors
跳转至:导航、​搜索

18.4. 选择器 — 高级 I/O 多路复用

3.4 版中的新功能。


源代码: :source:`Lib/selectors.py`



18.4.1. 介绍

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

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

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 事件的方法,具有可选的超时。 它是一个抽象基类,所以不能被实例化。 使用 DefaultSelectorSelectSelectorKqueueSelector 等之一。 如果您想专门使用一个实现,并且您的平台支持它。 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)