epoll原理

1、 epoll 与 poll/select

epoll是由一组系统调用组成。
     int epoll_create(int size);
     int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
     int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
     select/poll的缺点在于:
     1.每次调用时要重复地从用户态读入参数。
     2.每次调用时要重复地扫描文件描述符。
     3.每次在调用开始时,要把当前进程放入各个文件描述符的等待队列。在调用结束后,又把进程从各个等待队列中删除。
     在实际应用中,select/poll监视的文件描述符可能会非常多,如果每次只是返回一小部分,那么,这种情况下select/poll

显得不够高效。epoll的设计思路,是把select/poll单个的操作拆分为1个epoll_create+多个epoll_ctrl+一个epoll_wait。

=========每次select时的参数都需要拷贝到内核态; 返回时从内核态删除。

=========epoll_wait无参; 在epoll_ctrl中就已经拷贝到内核态、且仅拷贝一次。


2、epoll本身特点

0)epoll_wait/epoll_ctl是多线程安全的。底层的红黑树由mutex保护,ready list由spinlock保护。

1)一个fd上多个事件触发时, 是combination到一起返回的。 所以:

----if(which &EPOLLIN) dosomething;

----else if(which &EPOLLOUT) dosomething; 这种方式不太合适、可能漏掉通知。(客户端是应答式的就没问题了)

2)close就会将fd从epoll_set中移除

3)可以多线程同时进行epoll事件分发处理。 |EPOLLONESHOT、epoll_wait返回之后需要epoll_ctl(MOD)恢复


3、epoll的ET与LT

ET更快, 因为ET减少了epoll_wait的系统调用次数。 


ET缺省是ready状态; 直到EAGAIN。 只能用户nonblock

==========对于data socket, 应该是开始只注册读、 读完后处理数据只注册写、写完后只注册读这个过程重复【半双工】?  如果数据处理的逻辑很耗时,后面需要线程池来处理? 一个线程在epoll_wait的过程当中, 另外一个线程能epoll_ctl吗?

==========还是同时注册读写, 让epoll_wait频繁的醒来?


LT缺省是readiness状态。可用于block或者nonblock



4、问题与建议

1) 饥饿? 不止是epoll的问题, 也不是epoll的问题; 任何io分发器都会有这样的问题。应该由应用来解决。

2) event cache... ........           from "man epoll"


=====================================================================================

当epoll后面的数据处理逻辑比较慢时, 比如磁盘io?, 有两种方式提高性能:

1) epoll读到完整消息后, 将消息给worker线程处理

2)多线程epoll_wait+ONESHOT。


结论, 经过上述综合, 使用多线程+ONESHOT可能较好。

至于是LT还是ET?  如果不考虑饥饿的话, ET比较高效;  如果需要考虑饥饿的话呢



参考:

http://www.cnblogs.com/dkblog/archive/2010/12/08/1980680.html

http://blog.chinaunix.net/uid-20937170-id-4206879.html

http://bbs.csdn.net/topics/390370165

你可能感兴趣的:(epoll原理)