poll、select 和 epoll

2018/07/23

在一个 web server 程序中,我们需要读取 client 请求的输入,并且需要将服务端的数据返回给 client。在 linux(Unix)系统中,任何资源都是文件,即 fd(文件描述符),所以我们需要监控需要的 fd,以便可读时,读取 client 的输入,可写时,向 client 返回服务端的数据。

假设程序有 100 个 client 访问,那么就需要从 100 个 fd 中读取数据,那么怎么做呢?

可以为每一个 client 生成一个 thred 或者 process(线程或者进程)来处理请求,但是很显然当 client 越来越大的时候,就会非常消耗资源,因为(???)

select & poll

这两种方法是任何 Unix 系统都有的,epoll 只有 linux 有,他们的工作方式都是:

select 和 poll 的定义

poll 返回了很多可能的 fd 处理结果,而 select 只返回了输入/输出/错误(select 内部做了转换)

另外一个区别就是:如果只想知道 1,3,4,19 四个 fd 的信息,poll 会遍历所有的 19 个 fd,而 select 只会遍历这 4 个

虽然 select 好一点,但是他们实际上还是依靠循环实现的,所以时间负复杂度是O(N)

信号驱动 IO

当 fd 发生变化的时候,让内核给你发一个信号

什么时候会内核会发出信号呢,有两种模式

epoll

    #include <sys/epoll.h>
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

他的参数:

    #include <sys/epoll.h>
    int epoll_wait(int epfd, struct epoll_event *evlist, int maxevents, int timeout);

他的参数:

timeout 参数的含义:

epoll_wait 的返回值

poll select 和 epoll 的性能对比

# operations  |  poll  |  select   | epoll
10            |   0.61 |    0.73   | 0.41
100           |   2.9  |    3.0    | 0.42
1000          |  35    |   35      | 0.53
10000         | 990    |  930      | 0.66

参考