# 18.3. `select` - 等待I / O完成

This module provides access to the `select()` and `poll()` functions available in most operating systems, `devpoll()` available on Solaris and derivatives, `epoll()` available on Linux 2.5+ and `kqueue()` available on most BSD. 注意，在Windows上，它只适用于套接字；在其他操作系统上，它也适用于其他文件类型（特别是在Unix上，它在管道上工作）。它不能用于常规文件，以确定文件自上次读取以来是否已增长。

注意

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

模块定义如下：

exception `select.``error`

  已弃用的`OSError`别名。

  在版本3.3中已更改：在 PEP 3151之后，此类被设为`OSError`的别名。

`select.``devpoll`()

  （仅在Solaris和衍生产品上受支持。返回`/dev/poll`轮询对象；有关devpoll对象支持的方法，请参阅下面的/dev/poll Polling Objects一节。

  `devpoll()`对象链接到在实例化时允许的文件描述器的数量。如果你的程序减少这个值，`devpoll()`将失败。如果你的程序增加这个值，`devpoll()`可能返回一个不完整的活动文件列表描述器。

  新文件描述器是non-inheritable。

  版本3.3中的新功能。

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

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

  （仅在Linux 2.5.44及更高版本上受支持。）返回边沿轮询对象，可用作I / O事件的边沿或级别触发接口。sizehint已被弃用并完全被忽略。标志可以设置为`EPOLL_CLOEXEC`，这将导致在调用`os.execve()`时epoll描述器自动关闭。

  有关epolling对象支持的方法，请参见下面的Edge and Level Trigger Polling (epoll) Objects部分。

  `epoll`对象支持上下文管理协议：当在`with`语句中使用时，新文件描述器在块结束时自动关闭。

  新文件描述器是non-inheritable。

  在版本3.3中已更改：添加了标志参数。

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

`select.``poll`()

  （不受所有操作系统支持。）返回一个轮询对象，它支持注册和取消注册文件描述器，然后轮询它们的I / O事件；有关轮询对象支持的方法，请参阅下面的Polling Objects部分。

`select.``kqueue`()

  （仅在BSD上支持。返回一个内核队列对象；有关kqueue对象支持的方法，请参阅下面的Kqueue Objects部分。

  新文件描述器是non-inheritable。

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

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

  （仅在BSD上支持。返回内核事件对象；有关kevent对象支持的方法，请参阅下面的Kevent Objects部分。

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

  这是Unix `select()`系统调用的简单接口。前三个参数是“等待对象”的序列：使用名为`fileno()`的无参数方法表示文件描述器或对象的整数返回这样一个整数：

  - rlist：等待准备读取
  - wlist：等待准备写入
  - xlist：等待“异常条件”（请参阅​​系统认为此类条件的手册页）

  允许空序列，但三个空序列的接受是平台依赖性的。（已知在Unix上工作，但在Windows上不工作。）可选的timeout参数将超时指定为浮点数，以秒为单位。当省略timeout参数时，该功能阻塞，直到至少一个文件描述器准备就绪。超时值零指定轮询并从不阻止。

  返回值是准备好的对象列表的三倍：前三个参数的子集。当超时到达没有文件描述器变为准备好时，返回三个空列表。

  在序列中可接受的对象类型中有Python file objects（例如，`sys.stdin`或由`open()`或`os.popen()`返回的对象，`socket.socket()`。你也可以自己定义一个wrapper类，只要它有一个适当的`fileno()`方法（真的返回一个文件描述器，而不只是一个随机整数）。

  注意

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

  Changed in version 3.5: The function is now retried with a recomputed timeout when interrupted by a signal, except if the signal handler raises an exception (see PEP 475 for the rationale), instead of raising `InterruptedError`.

`select.``PIPE_BUF`

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

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

  版本3.2中的新功能。

## 18.3.1. `/dev/poll` Polling Objects

Solaris和衍生产品具有`/dev/poll`。`select()`是O（最高文件描述器），`poll()`是O（文件描述器的数目），`/dev/poll`

`/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()`对象的常量相同。默认值是常量`POLLIN`，`POLLPRI`和`POLLOUT`的组合。

  警告

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

`devpoll.``modify`(fd[, eventmask])

  此方法执行`unregister()`后跟`register()`。它是（有点）更有效率做同样明确。

`devpoll.``unregister`(fd)

  删除文件描述正在被轮询对象跟踪的器件。与`register()`方法一样，fd可以是一个整数，也可以是一个返回整数的`fileno()`方法的对象。

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

`devpoll.``poll`([timeout])

  调用注册文件描述器的集合，并返回一个包含`（fd， 事件）`有报告的事件或错误。fd是文件描述器，事件是一个位掩码，该位掩码为该描述器 - `POLLIN` `POLLOUT`以指示可以将描述器写入等等。空列表指示呼叫超时，并且没有文件描述器具有要报告的任何事件。如果给定timeout，则指定系统在返回之前等待事件的时间长度（以毫秒为单位）。如果省略timeout，-1或`None`，则调用将阻塞，直到此poll对象有事件为止。

  Changed in version 3.5: The function is now retried with a recomputed timeout when interrupted by a signal, except if the signal handler raises an exception (see PEP 475 for the rationale), instead of raising `InterruptedError`.

## 18.3.2. Edge and Level Trigger Polling (epoll) Objects

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

> eventmask

> Constant | Meaning
> --- | ---
> `EPOLLIN` | Available for read
> `EPOLLOUT` | Available for write
> `EPOLLPRI` | Urgent data for read
> `EPOLLERR` | Error condition happened on the assoc. fd
> `EPOLLHUP` | Hang up happened on the assoc. fd
> `EPOLLET` | Set Edge Trigger behavior, the default is Level Trigger behavior
> `EPOLLONESHOT` | Set one-shot behavior. After one event is pulled out, the fd is internally disabled
> `EPOLLRDNORM` | Equivalent to `EPOLLIN`
> `EPOLLRDBAND` | Priority data band can be read.
> `EPOLLWRNORM` | Equivalent to `EPOLLOUT`
> `EPOLLWRBAND` | Priority data may be written.
> `EPOLLMSG` | Ignored.

`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）

  Changed in version 3.5: The function is now retried with a recomputed timeout when interrupted by a signal, except if the signal handler raises an exception (see PEP 475 for the rationale), instead of raising `InterruptedError`.

## 18.3.3. Polling Objects

在大多数Unix系统上支持的`poll()`系统调用为同时为许多客户端提供服务的网络服务器提供了更好的可扩展性。`poll()`更好，因为系统调用只需要列出感兴趣的文件描述器，而`select()`构建位图，打开感兴趣的fds的位，然后之后必须再次线性扫描整个位图。`select()`是O（最高文件描述器），而`poll()`是O（文件描述器的数目）。

`poll.``register`(fd[, eventmask])

  注册文件描述器与轮询对象。对`poll()`方法的未来调用将检查文件描述器是否有任何未决的I / O事件。fd可以是整数，也可以是返回整数的`fileno()`方法的对象。文件对象实现`fileno()`，因此它们也可以用作参数。

  eventmask是描述要检查的事件类型的可选位掩码，可以是常量`POLLIN`，`POLLPRI`和`POLLOUT`，如下表所述。如果未指定，则使用的默认值将检查所有3种类型的事件。

  不变 | 含义
  --- | ---
  `POLLIN` | 有要读取的数据
  `POLLPRI` | 有紧急数据要读
  `POLLOUT` | 准备输出：写入不会阻塞
  `POLLERR` | 某种类型的错误条件
  `POLLHUP` | 挂了
  `POLLNVAL` | 请求无效：描述器不打开

  注册文件已经注册的描述器不是错误，并且与注册描述器完全一样的效果。

`poll.``modify`(fd, eventmask)

  修改已注册的fd。这与`寄存器（fd， eventmask）`具有相同的效果。尝试修改未曾注册的文件描述器会导致引发具有errno `ENOENT`的`OSError`异常。

`poll.``unregister`(fd)

  删除文件描述正在被轮询对象跟踪的器件。和`register()`方法一样，fd可以是一个整数或一个带有返回整数的`fileno()`方法的对象。

  尝试删除文件描述未曾注册的器件会引发`KeyError`异常。

`poll.``poll`([timeout])

  调用注册文件描述器的集合，并返回一个包含`（fd， 事件）`有报告的事件或错误。fd是文件描述器，事件是一个位掩码，该位掩码为该描述器 - `POLLIN` `POLLOUT`以指示可以将描述器写入等等。空列表指示呼叫超时，并且没有文件描述器具有要报告的任何事件。如果给定timeout，则指定系统在返回之前等待事件的时间长度（以毫秒为单位）。如果省略超时，否定或`None`，调用将阻塞，直到此轮询对象有事件。

  Changed in version 3.5: The function is now retried with a recomputed timeout when interrupted by a signal, except if the signal handler raises an exception (see PEP 475 for the rationale), instead of raising `InterruptedError`.

## 18.3.4. Kqueue Objects

`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或正整数
  - 超时秒（可能是浮动）

  Changed in version 3.5: The function is now retried with a recomputed timeout when interrupted by a signal, except if the signal handler raises an exception (see PEP 475 for the rationale), instead of raising `InterruptedError`.

## 18.3.5. Kevent Objects

https://www.freebsd.org/cgi/man.cgi?query=kqueue&amp；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` | Permitcontrol()返回事件
  `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_READ`和`KQ_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`

  用户定义的值。