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 轮询对象;有关 devpoll 对象支持的方法,请参阅下面的 /dev/poll 轮询对象 部分。

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) 2 元组。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

关联文件描述符上发生错误情况

EPOLLHUP

关联文件描述符上发生挂起

EPOLLET

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

EPOLLONESHOT

设置单次行为。在拉出一个事件后,fd 在内部被禁用

EPOLLEXCLUSIVE

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

EPOLLRDHUP

流套接字对端关闭连接或关闭连接的写入半部分。

EPOLLRDNORM

等同于 EPOLLIN

EPOLLRDBAND

优先级数据带可读。

EPOLLWRNORM

等同于 EPOLLOUT

EPOLLWRBAND

优先级数据可写入。

EPOLLMSG

忽略。

EPOLLWAKEUP

防止在事件等待期间休眠。

3.6 版本新增: 添加了 EPOLLEXCLUSIVE。它仅受 Linux 内核 4.5 或更高版本支持。

3.14 版本新增: 添加了 EPOLLWAKEUP。它仅受 Linux 内核 3.5 或更高版本支持。

epoll.close()

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

epoll.closed

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

epoll.fileno()

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

epoll.fromfd(fd)

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

epoll.register(fd[, eventmask])

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

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) 具有相同的效果。尝试修改从未注册的文件描述符会引发带有 errno ENOENTOSError 异常。

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()

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

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

用户定义值。