多路复用就绪通知技术:epoll简介

最近无意中接触到了tornado,该框架有优秀的大并发处理能力,其得益于底层实现的基于epoll的单线程异步架构。那么问题来了?什么是epoll呢,为什么这么牛能够做为游戏服务器呢? 之前见过这个词,但没去深究。这次就好好了解下,同时做个记录并推介给大家,有个记忆,在需要的时候再详学。只做简单原理介绍对比,不深究细节。

先说一个比较老的I/O复用技术,select

之前我自己的项目经历中使用过select,当时需要解决的问题很简单,需要在一个进程中监控2个socket做消息分发处理,但均是异步的,不确定什么时候有消息进来,所以就选用select来解决。

简单的代码思路如下,需要注意两点:

可以看到在循环里面,每次都需要重新设置侦听的集合,及时间参数。因为入参和出差是同一个参数,所以才需要这么处理;

每次select返回后,需要分别判断被侦听的I/O是否有数据;

从上面的代码似乎也没发现什么不好的地方,因为只监控了2个socket,也还好。但假设如果用select实现大量并发长链接,去除最大连接数的限制,每次都需要重新设置侦听的集合,并在select返回后逐个去判断是否有数据需要处理。加入监控了1000个,恰好是最后一个连接有数据,那岂不是前面999个都是浪费时间?很显然是这样。在并发数比较少的情况下还没问题,但如果在大量并发的情况下,那么性能随着数目的增加就会线性下降。

下面是一个用select实现的简单服务器端示例,基本架构无非就如此。可以感受下代码思路。

接下来看看今天的主角epoll

之所以出现epoll,那肯定是有比select优秀之处。经过了解后发现跟select相比,epoll确实显的更聪明。能用代码解释清楚的,尽量不要用文字描述。

从代码实现可以看出,在epoll_wait()返回后,即得到了所有需要处理的I/O描述符集合。直接逐个处理即可。不会浪费时间。同时也不需要像select重新设置侦听集,而是提供了灵活的ADD/MOD/DEL操作。

epoll的使用更简单,只有3个接口:

int epoll_create(int size)创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽;

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。第一个参数是epoll_create()的返回值,第二个参数表示动作,用三个宏来表示:

EPOLL_CTL_ADD:注册新的fd到epfd中;

EPOLL_CTL_MOD:修改已经注册的fd的监听事件;

EPOLL_CTL_DEL:从epfd中删除一个fd;

第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事;

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)等待事件的产生,类似于select()调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。

做个简单的对比,作为结尾

select 一次可以监测 FD_SETSIZE数量大小的描述符,FD_SETSIZE 通常是一个在 libc 编译时指定的数字,也就是对监测的数量有限制;

poll一次可以监测的描述符数量并没有限制,但撇开其它因素,我们每次都不得不检查就绪通知,线性扫描所有通过描述符,这样时间复杂度为 O(n)而且很慢,这点和select是一样的;

epoll没有这些固定限制,也不执行任何线性扫描。因此它可以更高效地执行和处理大量事件;

epoll与select/poll相比还有一个优势就是的数据处理是共享内存的方式,省去了数据拷贝的开销,而select和poll是数据拷贝的方式。

文中没提及poll是因为作为一个中间产物,既然已经有epoll了就不需要学习poll。它们的发展历程是select->poll->epoll,所以知道其存在即可。

能用代码说明的,尽量不要用语言

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180124G0PQ0100?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券