EPOLL的ET和LT模式

合集下载

关于Epoll,你应该知道的那些细节

关于Epoll,你应该知道的那些细节

关于Epoll,你应该知道的那些细节Epoll,位于头文件sys/epoll.h,是Linux系统上的I/O事件通知基础设施。

epoll API为Linux系统专有,于内核2.5.44中首次引入,glibc于2.3.2版本加入支持。

其它提供类似的功能的系统,包括FreeBSD kqueue,Solaris /dev/poll等。

Epoll APIEpoll API实现了与poll类似的功能:监测多个文件描述符上是否可以执行I/O操作。

支持边缘触发ET和水平触发LT,相比poll支持监测数量更多的文件描述符。

以下API用于创建和管理epoll实例:epoll_create:创建Epoll实例,并返回Epoll实例关联的文件描述符。

(最新的epoll_create1扩展了epoll_create的功能)create_ctl:注册关注的文件描述符。

注册于同一epoll实例的一组文件描述符被称为epoll set,可以通过进程对应的/proc/[pid]/fdinfo目录查看。

epoll_wait:等待I/O事件,如果当前没有任何注册事件处于可用状态,调用线程会被阻塞。

水平触发LT与边缘触发ETEpoll事件分发接口可以使用ET和LT两种模式。

两种模式的差别描述如下。

典型场景:1 管道(pipe)读端的文件描述符(rfd)注册于Epoll实例。

2 写者(Writer)向管道(pipe)写端写2KB的数据。

3 epoll_wait调用结束,返回rfd作为就绪的文件描述符。

4 管道读者(pipe reader) 从rfd读1KB的数据。

5 下一次epoll_wait调用。

如果rfd文件描述符使用EPOLLET(边缘触发)标记加入Epoll接口,第5步对epoll_wait 的调用可能会挂住,尽管文件输入缓冲区中仍然有可用数据;与此同时,远端实体由于已经发送数据,可能正在等待回应。

其原因是边缘触发模式仅在所监控的文件描述符状态发。

epoll的LT和ET使用EPOLLONESHOT

epoll的LT和ET使用EPOLLONESHOT

epoll的LT和ET使⽤EPOLLONESHOTepoll有两种触发的⽅式即LT(⽔平触发)和ET(边缘触发)两种,在前者,只要存在着事件就会不断的触发,直到处理完成,⽽后者只触发⼀次相同事件或者说只在从⾮触发到触发两个状态转换的时候⼉才触发。

这会出现下⾯⼀种情况,如果是多线程在处理,⼀个SOCKET事件到来,数据开始解析,这时候这个SOCKET⼜来了同样⼀个这样的事件,⽽你的数据解析尚未完成,那么程序会⾃动调度另外⼀个线程或者进程来处理新的事件,这造成⼀个很严重的问题,不同的线程或者进程在处理同⼀个SOCKET的事件,这会使程序的健壮性⼤降低⽽编程的复杂度⼤⼤增加!!即使在ET模式下也有可能出现这种情况!!解决这种现象有两种⽅法:第⼀种⽅法是在单独的线程或进程⾥解析数据,也就是说,接收数据的线程接收到数据后⽴刻将数据转移⾄另外的线程。

第⼆种⽅法就是本⽂要提到的EPOLLONESHOT这种⽅法,可以在epoll上注册这个事件,注册这个事件后,如果在处理写成当前的SOCKET后不再重新注册相关事件,那么这个事件就不再响应了或者说触发了。

要想重新注册事件则需要调⽤epoll_ctl重置⽂件描述符上的事件,这样前⾯的socket就不会出现竞态这样就可以通过⼿动的⽅式来保证同⼀SOCKET只能被⼀个线程处理,不会跨越多个线程。

看下⾯的代码:void Eepoll::ResetOneShot(int epollfd,SOCKET fd,bool bOne){epoll_eventevent;event.data.fd= fd;event.events= EPOLLIN | EPOLLET ;if(bOne){event.events |=EPOLLONESHOT;}if(-1 == epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&event)){perror("resetoneshotepoll_ctl error!");}}这⾥有⼀个问题,在操作ET模式下的EPOLL时,对EPOLLONESHOT没有什么太⼤的注意点,但是在LT时,就有⼀些注意的了。

深入理解epoll讲解

深入理解epoll讲解

深入理解epoll1、基本知识epoll是在2.6内核中提出的,是之前的select和poll的增强版本。

相对于select和poll 来说,epoll更加灵活,没有描述符限制。

epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。

2、epoll接口epoll操作过程需要三个接口,分别如下:[cpp] view plain copy 在CODE上查看代码片派生到我的代码片#include <sys/epoll.h>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);(1)int epoll_create(int size);创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。

这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。

需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在Linux下如果查看/proc/进程id/fd/,是能够看到这个fd 的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

(2)int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。

epoll原理详解及epoll反应堆模型

epoll原理详解及epoll反应堆模型

epoll原理详解及epoll反应堆模型⽂章⽬录⼀、epoll原理详解⼆、epoll的两种触发模式三、epoll反应堆模型 设想⼀个场景:有100万⽤户同时与⼀个进程保持着TCP连接,⽽每⼀时刻只有⼏⼗个或⼏百个TCP连接是活跃的(接收TCP包),也就是说在每⼀时刻进程只需要处理这100万连接中的⼀⼩部分连接。

那么,如何才能⾼效的处理这种场景呢?进程是否在每次询问操作系统收集有事件发⽣的TCP连接时,把这100万个连接告诉操作系统,然后由操作系统找出其中有事件发⽣的⼏百个连接呢?实际上,在Linux2.4版本以前,那时的select或者poll事件驱动⽅式是这样做的。

这⾥有个⾮常明显的问题,即在某⼀时刻,进程收集有事件的连接时,其实这100万连接中的⼤部分都是没有事件发⽣的。

因此如果每次收集事件时,都把100万连接的套接字传给操作系统(这⾸先是⽤户态内存到内核态内存的⼤量复制),⽽由操作系统内核寻找这些连接上有没有未处理的事件,将会是巨⼤的资源浪费,然后select和poll就是这样做的,因此它们最多只能处理⼏千个并发连接。

⽽epoll不这样做,它在Linux内核中申请了⼀个简易的⽂件系统,把原先的⼀个select或poll调⽤分成了3部分:1int epoll_create(int size);2int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);3int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);1. 调⽤epoll_create建⽴⼀个epoll对象(在epoll⽂件系统中给这个句柄分配资源);2. 调⽤epoll_ctl向epoll对象中添加这100万个连接的套接字;3. 调⽤epoll_wait收集发⽣事件的连接。

epoll工作模式详解

epoll工作模式详解

我们目前的网络模型大都是epoll的,因为epoll模型会比select模型性能高很多,尤其在大连接数的情况下,作为后台开发人员需要理解其中的原因。

select/epoll的特点select的特点:select 选择句柄的时候,是遍历所有句柄,也就是说句柄有事件响应时,select 需要遍历所有句柄才能获取到哪些句柄有事件通知,因此效率是非常低。

但是如果连接很少的情况下,select和epoll的LT触发模式相比,性能上差别不大。

这里要多说一句,select支持的句柄数是有限制的,同时只支持1024个,这个是句柄集合限制的,如果超过这个限制,很可能导致溢出,而且非常不容易发现问题,TAF就出现过这个问题,调试了n天,才发现:)当然可以通过修改linux的socket内核调整这个参数。

epoll的特点:epoll对于句柄事件的选择不是遍历的,是事件响应的,就是句柄上事件来就马上选择出来,不需要遍历整个句柄链表,因此效率非常高,内核将句柄用红黑树保存的。

对于epoll而言还有ET和LT的区别,LT表示水平触发,ET表示边缘触发,两者在性能以及代码实现上差别也是非常大的。

epoll的LT和ET的区别LT:水平触发,效率会低于ET触发,尤其在大并发,大流量的情况下。

但是LT对代码编写要求比较低,不容易出现问题。

LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心事件丢失的情况。

ET:边缘触发,效率非常高,在并发,大流量的情况下,会比LT少很多epoll的系统调用,因此效率高。

但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况。

下面举一个列子来说明LT和ET的区别(都是非阻塞模式,阻塞就不说了,效率太低):采用LT模式下,如果accept调用有返回就可以马上建立当前这个连接了,再epoll_wait 等待下次通知,和select一样。

但是对于ET而言,如果accpet调用有返回,除了建立当前这个连接外,不能马上就epoll_wait 还需要继续循环accpet,直到返回-1,且errno==EAGAIN,TAF里面的示例代码:if(ev.events & EPOLLIN){do{struct sockaddr_in stSockAddr;socklen_t iSockAddrSize = sizeof(sockaddr_in);TC_Socket cs;cs.setOwner(false);//接收连接TC_Socket s;s.init(fd, false, AF_INET);int iRetCode = s.accept(cs, (struct sockaddr *) &stSockAddr, iSockAddrSize);if (iRetCode > 0){…建立连接}else{//直到发生EAGAIN才不继续acceptif(errno == EAGAIN){break;}}}while(true);}同样,recv/send等函数,都需要到errno==EAGAIN从本质上讲:与LT相比,ET模型是通过减少系统调用来达到提高并行效率的。

epoll用法

epoll用法

epoll用法epoll是Linux内核提供的一种高效的I/O多路复用机制,可以监视多个文件描述符的状态,并在其中任何一个文件描述符就绪时通知应用程序进行相应的操作。

epoll在高并发网络应用中被广泛应用,它的使用方式也比较灵活,可以根据不同的需求选择不同的模式。

一、epoll概述epoll是Linux内核提供的一种高效的I/O多路复用机制,它可以监视多个文件描述符的状态,当其中任何一个文件描述符就绪时,就会通知应用程序进行相应的操作。

epoll是一种基于事件驱动的I/O模型,它可以同时处理大量的连接,而且不会因为连接数的增加而导致性能下降。

epoll的优点主要有以下几点:1. 高效:epoll采用了红黑树的数据结构,可以快速地定位就绪的文件描述符,而且不会因为连接数的增加而导致性能下降。

2. 灵活:epoll的工作模式有三种,分别是ET模式、LT模式和EPOLLONESHOT模式,可以根据不同的需求选择不同的模式。

3. 可扩展:epoll可以同时处理大量的连接,而且可以动态地增加或删除文件描述符,非常灵活。

二、epoll使用方法1. 创建epoll实例使用epoll需要先创建一个epoll实例,可以通过调用epoll_create函数来创建,该函数的原型如下:int epoll_create(int size);其中,size参数指定epoll实例中红黑树的节点个数,一般可以设置为1024。

该函数调用成功后,返回一个epoll实例的文件描述符,失败则返回-1。

2. 添加文件描述符到epoll实例使用epoll需要将要监视的文件描述符添加到epoll实例中,可以通过调用epoll_ctl函数来实现,该函数的原型如下:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);其中,epfd参数是epoll实例的文件描述符,op参数指定要进行的操作,可以是EPOLL_CTL_ADD、EPOLL_CTL_MOD或EPOLL_CTL_DEL,fd参数是要添加、修改或删除的文件描述符,event参数是一个epoll_event结构体,用于指定要监视的事件类型,该结构体的定义如下:struct epoll_event {__uint32_t events; // 监控的事件类型epoll_data_t data; // 用户数据};events参数指定要监视的事件类型,可以是EPOLLIN、EPOLLOUT、EPOLLRDHUP、EPOLLERR等,具体含义如下:EPOLLIN:表示文件描述符可读。

探讨epoll原理(红黑树、rdlist的实现)

探讨epoll原理(红黑树、rdlist的实现)

探讨epoll原理(红⿊树、rdlist的实现)
再谈epoll
原理
关键概念:eventpoll结构体(fd管理器)、ep_poll_callback(回调)、rdlist(双向链表)、epitem(epoll管理的结点)
每个epoll对象都有⼀个独⽴的eventpoll结构体,通过eventpoll管理存放epoll_ctl添加的事件集合,这些事件以epitem为结点挂载到红⿊树上。

添加到epoll中的事件,都会与设备驱动建⽴回调关系,当相应事件发⽣时该回调将事件对应的epitem结点加⼊
rdlist即可;
因此,当⽤户调⽤epoll_wait是指上内核只检查了rdlist是否为空,若⾮空将其拷贝到⽤户态并返回触发事件数量。

可以说:红⿊树+rdlist+回调铸就了epoll的⾼效。

为何⽀持百万并发
不⽤重复传递事件集合
epoll初始化时,内核开辟了epoll缓冲区,缓冲区内事件以epitem结点挂载到红⿊树上,通过epoll_ctl的任何操作都是O(logN)
epoll_wait调⽤仅需观察rdlist是否为空,若⾮空则拷贝rdlist到⽤户空间并返回触发事件数量,⽆需遍历
向内核中断处理注册回调,⼀旦关⼼的事件触发,回调⾃动将socket对应的epitem添加到rdlist中
ET和LT,来⾃电⼦的概念
ET边沿触发:⽆论事件是否处理完毕,仅触发⼀次
LT⽔平触发:只要事件没有处理完毕,每⼀次epoll_wait都触发该事件。

Linux网络编程的5种IO模型:多路复用(select、poll、epoll)

Linux网络编程的5种IO模型:多路复用(select、poll、epoll)

Linux⽹络编程的5种IO模型:多路复⽤(select、poll、epoll)背景我们在上⼀讲中,对于其中的阻塞/⾮阻塞IO 进⾏了说明。

这⼀讲我们来看多路复⽤机制。

IO复⽤模型 ( I/O multiplexing )所谓I/O多路复⽤机制,就是说通过⼀种机制,可以监视多个描述符,⼀旦某个描述符就绪(⼀般是读就绪或者写就绪),能够通知程序进⾏相应的读写操作。

这种机制的使⽤需要额外的功能来配合: select、poll、epollselect、poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后⾃⼰负责进⾏读写,也就是说这个读写过程是阻塞的。

select时间复杂度O(n)它仅仅知道了,有I/O事件发⽣了,却并不知道是哪那⼏个流(可能有⼀个,多个,甚⾄全部),我们只能⽆差别轮询所有流,找出能读出数据,或者写⼊数据的流,对他们进⾏操作。

所以select具有O(n)的⽆差别轮询复杂度,同时处理的流越多,⽆差别轮询时间就越长。

poll时间复杂度O(n)poll本质上和select没有区别,它将⽤户传⼊的数组拷贝到内核空间,然后查询每个fd对应的设备状态,但是它没有最⼤连接数的限制,原因是它是基于链表来存储的.epoll时间复杂度O(1)epoll可以理解为event poll,不同于忙轮询和⽆差别轮询,epoll会把哪个流发⽣了怎样的I/O事件通知我们。

所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。

(复杂度降低到了O(1))在多路复⽤IO模型中,会有⼀个内核线程不断去轮询多个socket的状态,只有当真正读写事件发⽣时,才真正调⽤实际的IO读写操作。

因为在多路复⽤IO模型中,只需要使⽤⼀个线程就可以管理多个socket,系统不需要建⽴新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有读写事件进⾏时,才会使⽤IO资源,所以它⼤⼤减少了资源占⽤。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

EPOLL的ET和LT模式EPOLL的ET和LT模式近日又继续学习了一下EPOLL的工作模式,这会基本上搞清楚了,因而撰写了此篇文档进行描述。

先来一段网上的介绍文档:EPOLL事件分发系统可以运转在两种模式下:Edge Triggered (ET)、Level Triggered (LT)。

LT是缺省的工作方式,并且同时支持block和no-block socket;在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。

如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。

传统的select/poll 都是这种模型的代表。

ET是高速工作方式,只支持no-block socket。

在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。

然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了。

但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知。

后面才是我想说的内容,既然ET模式是高速模式,那我们进行服务器开发是一定要使用的了,可是查遍文档,也没有找到ET模式的设置方法,到底如何设置和使用呢?通过反复测试,终于搞明白“EPOLLET”就是ET模式的设置了,也许是我太笨所以才迷惑这么久了,以下就是将TCP套接字hSocket和epoll关联起来的代码:struct epoll_event struEvent;struEvent.events = EPOLLIN | EPOLLOUT | EPOLLET;struEvent.data.fd = hSocket;epoll_ctl(m_hEpoll, EPOLL_CTL_ADD, hSocket, &struEvent);如果将监听套接字m_hListenSocket和epoll关联起来,则代码如下:struct epoll_event struEvent;struEvent.events = EPOLLIN | EPOLLET;struEvent.data.fd = m_hListenSocket;epoll_ctl(m_hEpoll, EPOLL_CTL_ADD, m_hListenSocket, &struEvent);如果想使用LT模式,直接把事件的赋值修改为以下即可,也许这就是缺省的意义吧。

struEvent.events = EPOLLIN | EPOLLOUT; //用户TCP套接字struEvent.events = EPOLLIN; //监听TCP套接字不过,通过我的测试确定,这两种模式的性能差距还是非常大的,最大可以达到10倍。

100个连接的压力测试,其他环境都相同,LT模式CPU消耗99%、ET模式15%。

epoll精髓在linux的网络编程中,很长的时间都在使用select来做事件触发。

在linux新的内核中,有了一种替换它的机制,就是epoll。

相比于select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。

因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。

并且,在linux/posix_types.h头文件有这样的声明:#define __FD_SETSIZE 1024表示select最多同时监听1024个fd,当然,可以通过修改头文件再重编译内核来扩大这个数目,但这似乎并不治本。

epoll的接口非常简单,一共就三个函数:1. int epoll_create(int size);创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。

这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。

需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux 下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

2. 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,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:struct epoll_event {__uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */};events可以是以下几个宏的集合:EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);EPOLLOUT:表示对应的文件描述符可以写;EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);EPOLLERR:表示对应的文件描述符发生错误;EPOLLHUP:表示对应的文件描述符被挂断;EPOLLET:将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。

EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);等待事件的产生,类似于select()调用。

参数events用来从内核得到事件的集合,maxevents告之内核这个秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。

该函数返回需要处理的事件数目,如返回0表示已超时。

--------------------------------------------------------------------------------------------从man手册中,得到ET和LT的具体描述如下EPOLL事件有两种模型:Edge Triggered (ET)Level Triggered (LT)假如有这样一个例子:1. 我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符2. 这个时候从管道的另一端被写入了2KB的数据3. 调用epoll_wait(2),并且它会返回RFD,说明它已经准备好读取操作4. 然后我们读取了1KB的数据5. 调用epoll_wait(2)......Edge Triggered 工作模式:如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。

只有在监视的文件句柄上发生了某个事件的时候ET 工作模式才会汇报事件。

因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。

在上面的例子中,会有一个事件产生在RFD句柄上,因为在第2步执行了一个写操作,然后,事件将会在第3步被销毁。

因为第4步的读取操作没有读空文件输入缓冲区内的数据,因此我们在第5步调用epoll_wait(2)完成后,是否挂起是不确定的。

epoll 工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。

最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。

i 基于非阻塞文件句柄ii 只有当read(2)或者write(2)返回EAGAIN时才需要挂起,等待。

但这并不是说每次read()时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read()返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。

Level Triggered 工作模式相反的,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll(2),并且无论后面的数据是否被使用,因此他们具有同样的职能。

因为即使使用ET模式的epoll,在收到多个chunk的数据的时候仍然会产生多个事件。

调用者可以设定EPOLLONESHOT标志,在epoll_wait(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。

因此当EPOLLONESHOT设定后,使用带有EPOLL_CTL_MOD标志的epoll_ctl(2)处理文件句柄就成为调用者必须作的事情。

然后详细解释ET, LT:LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。

如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。

传统的select/poll都是这种模型的代表.ET(edge-triggered)是高速工作方式,只支持no-block socket。

在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。

然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。

但是请注意,如果一直不对这个fd 作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认(这句话不理解)。

在许多测试中我们会看到如果没有大量的idle -connection或者dead-connection,epoll的效率并不会比select/poll高很多,但是当我们遇到大量的idle- connection(例如WAN环境中存在大量的慢速连接),就会发现epoll的效率大大高于select/poll。

相关文档
最新文档