Skip to main content

18.3. select —等待I/O完成


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

注解

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

模块定义如下:

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事件的边沿或级别触发接口。 sizehintflags 已被弃用并完全被忽略。

有关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() 返回的套接字对象。你也可以自己定义一个 wrapper 类,只要它有一个合适的 fileno() 方法(真正返回一个文件描述符,而不只是一个随机整数)。

注解

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

在 3.5 版更改: 该函数现在在信号中断时重新计算超时,除非信号处理程序引发异常(请参阅 PEP 475 的原因),而不是提高 InterruptedError

select.PIPE_BUF

当管道已报告为已准备好由 select()poll() 或此模块中的另一个接口进行写入时,可以写入而不会阻塞到管道的最小字节数。这不适用于其他类型的文件状对象,如套接字。

此值由POSIX保证至少为512.可用性:Unix。

3.2 新版功能.

18.3.1. /dev/poll 轮询对象

Solaris和衍生产品有 /dev/poll。虽然 select() 是O(最高文件描述符),poll() 是O(文件描述符的数目),/dev/poll 是O(活动文件描述符)。

/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

18.3.2. 边缘和级别触发器轮询(epoll)对象

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

eventmask

不变

含义

EPOLLIN

可供阅读

EPOLLOUT

可用于写入

EPOLLPRI

紧急数据要读

EPOLLERR

在assoc上发生错误条件。 fd

EPOLLHUP

挂断发生在assoc。 fd

EPOLLET

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

EPOLLONESHOT

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

EPOLLEXCLUSIVE

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

EPOLLRDHUP

流套接字对等关闭连接或关闭写半连接。

EPOLLRDNORM

相当于 EPOLLIN

EPOLLRDBAND

可以读取优先级数据带。

EPOLLWRNORM

相当于 EPOLLOUT

EPOLLWRBAND

可以写入优先级数据。

EPOLLMSG

忽略。

epoll.close()

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

epoll.closed

True 如果epoll对象被关闭。

epoll.fileno()

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

epoll.fromfd(fd)

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

epoll.register(fd[, eventmask])

向epoll对象注册fd描述符。

epoll.modify(fd, eventmask)

修改注册文件描述符。

epoll.unregister(fd)

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

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

等待事件。超时秒(float)

在 3.5 版更改: 该函数现在在信号中断时重新计算超时,除非信号处理程序引发异常(请参阅 PEP 475 的原因),而不是提高 InterruptedError

18.3.3. 轮询对象

在大多数Unix系统上支持的 poll() 系统调用为同时为许多客户机提供服务的网络服务器提供了更好的可扩展性。 poll() 规模更好,因为系统调用只需要列出感兴趣的文件描述符,而 select() 构建位图,打开感兴趣的fds的位,然后必须再次线性扫描整个位图。 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,调用将阻塞,直到此poll对象有一个事件。

在 3.5 版更改: 该函数现在在信号中断时重新计算超时,除非信号处理程序引发异常(请参阅 PEP 475 的原因),而不是提高 InterruptedError

18.3.4. Kqueue对象

kqueue.close()

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

kqueue.closed

True 如果kqueue对象关闭。

kqueue.fileno()

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

kqueue.fromfd(fd)

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

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

低级别接口kevent

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

  • max_events必须为0或正整数

  • 超时秒(可以浮动)

在 3.5 版更改: 该函数现在在信号中断时重新计算超时,除非信号处理程序引发异常(请参阅 PEP 475 的原因),而不是提高 InterruptedError

18.3.5. Kevent对象

https://www.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

监视进程标识上的事件

KQ_FILTER_NETDEV

观看网络设备上的活动[Mac OS X上不可用]

KQ_FILTER_SIGNAL

当监视信号传递到进程时返回

KQ_FILTER_TIMER

建立任意定时器

kevent.flags

过滤操作。

不变

含义

KQ_EV_ADD

添加或修改事件

KQ_EV_DELETE

从队列中删除事件

KQ_EV_ENABLE

Permitscontrol()返回事件

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 过滤器标记(在Mac OS X上不可用):

不变

含义

KQ_NOTE_LINKUP

链接起来

KQ_NOTE_LINKDOWN

链接已关闭

KQ_NOTE_LINKINV

链路状态无效

kevent.data

过滤特定数据。

kevent.udata

用户定义的值。