Preface

可以从 Go 源码目录结构和对应代码文件了解 Go 在不同平台下的网络 I/O 模式的实现。比如,在 Linux 系统下基于 epoll,freeBSD 系统下基于 kqueue,以及 Windows 系统下基于 iocp

由于代码运行环境主要是Linux,所以我们主要讲epoll

所谓 I/O 多路复用指的就是 select/epoll 这一系列的多路选择器:支持单一线程同时监听多个文件描述符(I/O 事件),阻塞等待,并在其中某个文件描述符可读写时收到通知。

Select

int select(int nfds,
						fd_set *restrict readfds,
						fd_set *restrict writefds,
						fd_set *restrict errorfds,
						struct timeval *restrict timeout);

readfdswritefds、和errorfds是三个文件描述符集合。select会遍历每个集合的前nfds个描述符,分别找到可以读取、可以写入、发生错误的描述符,统称为就绪的描述符。

timeout表示调用select的阻塞时长,如果所有文件描述符都未就绪,就阻塞调用进程,直到某个描述符就绪,或者阻塞超过设置的timeout后,返回。如果timeout参数为null,会无限阻塞直到某个描述符就行;如果为0会立即返回,不阻塞。

缺点:

  1. 单个进程所打开的FD是有一定限制的,它由**FD_SETSIZE**设置,默认值是1024;
  2. 每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大;
  3. 每次 kernel 都需要线性扫描整个 fd_set,所以随着监控的描述符 fd 数量增长,其 I/O 性能会线性下降;

Epoll

epoll是select的增强版本,避免了“性能开销大”和“文件描述符数量少”的两个缺点。

structure