select — 等待 I/O 完成


此模块提供对大多数操作系统中可用的 select()poll() 函数的访问权限,以及 Solaris 及其衍生产品中可用的 devpoll(),Linux 2.5+ 上可用的 epoll() 以及大多数 BSD 上可用的 kqueue()。请注意,在 Windows 上,它仅适用于套接字;在其他操作系统上,它也适用于其他文件类型(特别是在 Unix 上,它适用于管道)。它不能用于常规文件,以确定文件自上次读取后是否已增长。

注意

selectors 模块允许高级且高效的 I/O 多路复用,它基于 select 模块原语构建。除非用户想要精确控制所使用的操作系统级别原语,否则建议使用 selectors 模块。

可用性:非 WASI。

此模块在 WebAssembly 上不起作用或不可用。有关更多信息,请参见WebAssembly 平台

该模块定义了以下内容

exception select.error

OSError 的已弃用别名。

在 3.3 版本中更改:根据 PEP 3151,此类已成为 OSError 的别名。

select.devpoll()

(仅在 Solaris 及其衍生产品上支持。)返回一个 /dev/poll 轮询对象;请参阅下面的/dev/poll 轮询对象部分,了解 devpoll 对象支持的方法。

devpoll() 对象链接到实例化时允许的文件描述符的数量。如果您的程序减少此值,则 devpoll() 将失败。如果您的程序增加此值,则 devpoll() 可能会返回不完整的活动文件描述符列表。

新的文件描述符是不可继承的

在 3.3 版本中添加。

在 3.4 版本中更改:新的文件描述符现在是不可继承的。

select.epoll(sizehint=-1, flags=0)

(仅在 Linux 2.5.44 及更高版本上支持。)返回一个边缘轮询对象,该对象可用作 I/O 事件的边缘或电平触发接口。

sizehint 会告知 epoll 要注册的预期事件数。它必须为正数,或 -1 以使用默认值。它仅在 epoll_create1() 不可用的较旧系统上使用;否则它不起作用(尽管仍然会检查其值)。

flags 已弃用并被完全忽略。但是,当提供时,其值必须为 0select.EPOLL_CLOEXEC,否则会引发 OSError

有关 epolling 对象支持的方法,请参阅下面的边缘和电平触发轮询 (epoll) 对象部分。

epoll 对象支持上下文管理协议:在 with 语句中使用时,新的文件描述符会在块的末尾自动关闭。

新的文件描述符是不可继承的

在 3.3 版本中更改:添加了 flags 参数。

在 3.4 版本中更改:添加了对 with 语句的支持。新的文件描述符现在是不可继承的。

自 3.4 版本起已弃用:flags 参数。现在默认使用 select.EPOLL_CLOEXEC。使用 os.set_inheritable() 使文件描述符可继承。

select.poll()

(并非所有操作系统都支持。)返回一个轮询对象,该对象支持注册和取消注册文件描述符,然后轮询它们的 I/O 事件;有关轮询对象支持的方法,请参阅下面的轮询对象部分。

select.kqueue()

(仅在 BSD 上支持。)返回一个内核队列对象;有关 kqueue 对象支持的方法,请参阅下面的Kqueue 对象部分。

新的文件描述符是不可继承的

在 3.4 版本中更改:新的文件描述符现在是不可继承的。

select.kevent(ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=0)

(仅在 BSD 上支持。)返回一个内核事件对象;有关 kevent 对象支持的方法,请参阅下面的Kevent 对象部分。

select.select(rlist, wlist, xlist[, timeout])

这是对 Unix select() 系统调用的直接接口。前三个参数是“可等待对象”的可迭代对象:要么是表示文件描述符的整数,要么是具有名为 fileno() 的无参数方法并返回此类整数的对象

  • rlist:等待直到准备好读取

  • wlist:等待直到准备好写入

  • xlist: 等待“异常情况”(请参阅系统手册页以了解您的系统认为的此类情况)。

允许使用空的可迭代对象,但接受三个空的可迭代对象是平台相关的。(已知在 Unix 上可以工作,但在 Windows 上不行。)可选的 timeout 参数以秒为单位指定超时时间,该值是浮点数。当省略 timeout 参数时,函数将阻塞,直到至少有一个文件描述符准备就绪。超时值为零指定轮询,并且永不阻塞。

返回值是一个由三个列表组成的三元组,其中包含准备就绪的对象:是前三个参数的子集。当在没有文件描述符变为就绪的情况下达到超时时,将返回三个空列表。

可迭代对象中可接受的对象类型包括 Python 文件对象(例如 sys.stdin,或由 open()os.popen() 返回的对象),以及由 socket.socket() 返回的套接字对象。您也可以自己定义一个包装器类,只要它具有适当的 fileno() 方法(该方法实际上返回一个文件描述符,而不仅仅是一个随机整数)。

注意

Windows 上的文件对象是不可接受的,但套接字可以。在 Windows 上,底层的 select() 函数由 WinSock 库提供,并且不处理不源自 WinSock 的文件描述符。

在 3.5 版本中更改: 现在,当被信号中断时,该函数将使用重新计算的超时时间重试,除非信号处理程序引发异常(请参阅PEP 475 中的基本原理),而不是引发 InterruptedError

select.PIPE_BUF

当管道被 select()poll() 或此模块中的其他接口报告为准备好写入时,可以无阻塞写入管道的最小字节数。这不适用于其他类型的文件类对象,例如套接字。

POSIX 保证此值至少为 512。

可用性:Unix

在 3.2 版本中添加。

/dev/poll 轮询对象

Solaris 和衍生产品具有 /dev/poll。虽然 select()O(最高文件描述符),并且 poll()O(文件描述符的数量),但 /dev/pollO(活动文件描述符)。

/dev/poll 的行为非常接近标准的 poll() 对象。

devpoll.close()

关闭轮询对象的文件描述符。

在 3.4 版本中添加。

devpoll.closed

如果轮询对象已关闭,则为 True

在 3.4 版本中添加。

devpoll.fileno()

返回轮询对象的文件描述符编号。

在 3.4 版本中添加。

devpoll.register(fd[, eventmask])

向轮询对象注册文件描述符。将来对 poll() 方法的调用将检查文件描述符是否具有任何挂起的 I/O 事件。fd 可以是整数,也可以是具有返回整数的 fileno() 方法的对象。文件对象实现了 fileno(),因此它们也可以用作参数。

eventmask 是一个可选的位掩码,描述您要检查的事件类型。常量与 poll() 对象相同。默认值是常量 POLLINPOLLPRIPOLLOUT 的组合。

警告

注册已经注册的文件描述符不是错误,但结果是未定义的。适当的操作是先取消注册或修改它。与 poll() 相比,这是一个重要的区别。

devpoll.modify(fd[, eventmask])

此方法执行 unregister(),然后执行 register()。它比显式执行相同操作更有效率(一点)。

devpoll.unregister(fd)

删除由轮询对象跟踪的文件描述符。与 register() 方法一样,fd 可以是整数或具有返回整数的 fileno() 方法的对象。

尝试删除从未注册的文件描述符会被安全地忽略。

devpoll.poll([timeout])

轮询一组已注册的文件描述符,并返回一个可能为空的列表,其中包含 (fd, event) 二元组,表示具有要报告的事件或错误的文件描述符。fd 是文件描述符,event 是一个位掩码,为该描述符报告的事件设置了位 - POLLIN 用于等待输入,POLLOUT 表示该描述符可以写入,依此类推。空列表表示调用超时,并且没有文件描述符有任何事件要报告。如果给出 timeout,则它以毫秒为单位指定系统在返回之前等待事件的时间长度。如果省略 timeout,-1 或 None,则调用将阻塞,直到此轮询对象发生事件。

在 3.5 版本中更改: 现在,当被信号中断时,该函数将使用重新计算的超时时间重试,除非信号处理程序引发异常(请参阅PEP 475 中的基本原理),而不是引发 InterruptedError

边缘和电平触发轮询 (epoll) 对象

https://linux.die.net/man/4/epoll

eventmask

常量

含义

EPOLLIN

可用于读取

EPOLLOUT

可用于写入

EPOLLPRI

用于读取的紧急数据

EPOLLERR

关联的 fd 上发生错误情况

EPOLLHUP

关联的 fd 上发生挂断

EPOLLET

设置边缘触发行为,默认行为是电平触发行为

EPOLLONESHOT

设置一次性行为。在提取一个事件后,fd 会在内部被禁用

EPOLLEXCLUSIVE

当关联的 fd 发生事件时,仅唤醒一个 epoll 对象。默认值(如果未设置此标志)是唤醒轮询 fd 的所有 epoll 对象。

EPOLLRDHUP

流套接字对等方关闭了连接或关闭了连接的写入一半。

EPOLLRDNORM

等效于 EPOLLIN

EPOLLRDBAND

可以读取优先级数据带。

EPOLLWRNORM

等效于 EPOLLOUT

EPOLLWRBAND

可以写入优先级数据。

EPOLLMSG

已忽略。

在 3.6 版本中添加: 添加了 EPOLLEXCLUSIVE。它仅受 Linux Kernel 4.5 或更高版本支持。

epoll.close()

关闭 epoll 对象的控制文件描述符。

epoll.closed

如果 epoll 对象已关闭,则为 True

epoll.fileno()

返回控制 fd 的文件描述符编号。

epoll.fromfd(fd)

从给定的文件描述符创建一个 epoll 对象。

epoll.register(fd[, eventmask])

向 epoll 对象注册一个文件描述符。

epoll.modify(fd, eventmask)

修改已注册的文件描述符。

epoll.unregister(fd)

从 epoll 对象中移除已注册的文件描述符。

在 3.9 版本中更改: 该方法不再忽略 EBADF 错误。

epoll.poll(timeout=None, maxevents=-1)

等待事件。超时时间以秒为单位(浮点数)。

在 3.5 版本中更改: 该函数现在会在被信号中断时,使用重新计算的超时时间进行重试,除非信号处理程序引发异常 (请参阅 PEP 475 获取理由),而不是引发 InterruptedError

轮询对象

在大多数 Unix 系统上支持的 poll() 系统调用为同时服务于大量客户端的网络服务器提供了更好的可扩展性。poll() 具有更好的可扩展性,因为系统调用只需要列出感兴趣的文件描述符,而 select() 则会构建一个位图,为感兴趣的 fd 打开位,然后之后必须再次线性扫描整个位图。select()O(最高文件描述符) 的复杂度,而 poll()O(文件描述符数量) 的复杂度。

poll.register(fd[, eventmask])

向轮询对象注册文件描述符。将来对 poll() 方法的调用将检查文件描述符是否具有任何挂起的 I/O 事件。fd 可以是整数,也可以是具有返回整数的 fileno() 方法的对象。文件对象实现了 fileno(),因此它们也可以用作参数。

eventmask 是一个可选的位掩码,描述了您要检查的事件类型,可以是常量 POLLINPOLLPRIPOLLOUT 的组合,如下表所述。 如果未指定,则使用的默认值将检查所有 3 种类型的事件。

常量

含义

POLLIN

有数据可读取

POLLPRI

有紧急数据可读取

POLLOUT

准备好输出:写入不会阻塞

POLLERR

某种类型的错误情况

POLLHUP

挂起

POLLRDHUP

流套接字对等方关闭了连接,或关闭了连接的写入一半

POLLNVAL

无效请求:描述符未打开

注册一个已经注册的文件描述符不是错误,并且与只注册一次该描述符具有相同的效果。

poll.modify(fd, eventmask)

修改已注册的 fd。这与 register(fd, eventmask) 具有相同的效果。尝试修改从未注册的文件描述符会导致引发 OSError 异常,errno 为 ENOENT

poll.unregister(fd)

删除轮询对象正在跟踪的文件描述符。就像 register() 方法一样,fd 可以是整数或具有 fileno() 方法(返回整数)的对象。

尝试删除从未注册的文件描述符会导致引发 KeyError 异常。

poll.poll([timeout])

轮询已注册文件描述符的集合,并返回一个可能为空的列表,其中包含具有要报告的事件或错误的描述符的 (fd, event) 2 元组。fd 是文件描述符,event 是一个位掩码,为该描述符报告的事件设置了位 — POLLIN 表示等待输入,POLLOUT 表示可以写入该描述符,依此类推。 空列表表示调用超时且没有文件描述符有任何事件要报告。 如果给定了 timeout,则它指定系统在返回之前等待事件的时间长度(以毫秒为单位)。如果省略了 timeout,或者为负数或 None,则调用将阻塞,直到此轮询对象发生事件为止。

在 3.5 版本中更改: 该函数现在会在被信号中断时,使用重新计算的超时时间进行重试,除非信号处理程序引发异常 (请参阅 PEP 475 获取理由),而不是引发 InterruptedError

Kqueue 对象

kqueue.close()

关闭 kqueue 对象的控制文件描述符。

kqueue.closed

如果 kqueue 对象已关闭,则为 True

kqueue.fileno()

返回控制 fd 的文件描述符编号。

kqueue.fromfd(fd)

从给定的文件描述符创建一个 kqueue 对象。

kqueue.control(changelist, max_events[, timeout]) eventlist

kevent 的底层接口

  • changelist 必须是 kevent 对象或 None 的可迭代对象

  • max_events 必须为 0 或正整数

  • 超时时间以秒为单位(可以是浮点数); 默认值为 None,表示永远等待

在 3.5 版本中更改: 该函数现在会在被信号中断时,使用重新计算的超时时间进行重试,除非信号处理程序引发异常 (请参阅 PEP 475 获取理由),而不是引发 InterruptedError

Kevent 对象

https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2

kevent.ident

用于标识事件的值。解释取决于过滤器,但通常是文件描述符。在构造函数中,ident 可以是 int 或具有 fileno() 方法的对象。kevent 在内部存储整数。

kevent.filter

内核过滤器的名称。

常量

含义

KQ_FILTER_READ

接受一个描述符,并在有数据可读取时返回

KQ_FILTER_WRITE

接受一个描述符,并在有数据可写入时返回

KQ_FILTER_AIO

AIO 请求

KQ_FILTER_VNODE

fflag 中监视的一个或多个请求的事件发生时返回

KQ_FILTER_PROC

监视进程 id 的事件

KQ_FILTER_NETDEV

监视网络设备上的事件 [在 macOS 上不可用]

KQ_FILTER_SIGNAL

每当受监视的信号传递给进程时返回

KQ_FILTER_TIMER

建立一个任意定时器

kevent.flags

过滤器动作。

常量

含义

KQ_EV_ADD

添加或修改一个事件

KQ_EV_DELETE

从队列中移除一个事件

KQ_EV_ENABLE

允许control()返回事件

KQ_EV_DISABLE

禁用事件

KQ_EV_ONESHOT

在第一次发生后移除事件

KQ_EV_CLEAR

在检索到事件后重置状态

KQ_EV_SYSFLAGS

内部事件

KQ_EV_FLAG1

内部事件

KQ_EV_EOF

过滤器特定的 EOF 条件

KQ_EV_ERROR

请参阅返回值

kevent.fflags

过滤器特定的标志。

KQ_FILTER_READKQ_FILTER_WRITE 过滤器标志

常量

含义

KQ_NOTE_LOWAT

套接字缓冲区的低水位标记

KQ_FILTER_VNODE 过滤器标志

常量

含义

KQ_NOTE_DELETE

调用了 unlink()

KQ_NOTE_WRITE

发生了写入

KQ_NOTE_EXTEND

文件被扩展

KQ_NOTE_ATTRIB

一个属性被更改

KQ_NOTE_LINK

链接计数已更改

KQ_NOTE_RENAME

文件被重命名

KQ_NOTE_REVOKE

对该文件的访问被撤销

KQ_FILTER_PROC 过滤器标志

常量

含义

KQ_NOTE_EXIT

进程已退出

KQ_NOTE_FORK

进程已调用 fork()

KQ_NOTE_EXEC

进程已执行一个新进程

KQ_NOTE_PCTRLMASK

内部过滤器标志

KQ_NOTE_PDATAMASK

内部过滤器标志

KQ_NOTE_TRACK

fork() 中跟踪进程

KQ_NOTE_CHILD

NOTE_TRACK 在子进程上返回

KQ_NOTE_TRACKERR

无法附加到子进程

KQ_FILTER_NETDEV 过滤器标志(在 macOS 上不可用)

常量

含义

KQ_NOTE_LINKUP

链接已启动

KQ_NOTE_LINKDOWN

链接已断开

KQ_NOTE_LINKINV

链接状态无效

kevent.data

过滤器特定数据。

kevent.udata

用户定义的值。