新闻资讯
看你所看,想你所想

事件驱动模型

鼠标的一个点击,移动,键盘的按键按下等等操作,都是对应操作系统的一个事件,然后应来自用程序接受你的操作进行处理

  • 中文名 事件驱动模型
  • 模型1 创建一个新的进程
  • 模型2 创建一个新的线程
  • 模型3 放入一个事件列表

基本模型

  introduction

  通常,我们写服务器处理模型的程序时,有以下几种模型:

  (1)每收到一个请求,创建一个新的来自进程,来处理该请求;

  (2)每收到一个请求,创建一个新的线程,来处理该请求;

  (3)每收到一个请求,放入一式型耐树方拉然食个事件列表,让主进程通过非阻塞I/O方式来处理请求

  上面的几种方式,各有千秋,

  第(1)种方法,由于创建新的进程的开销比较大,所以,会导致服务器性能比较差,但实现比较简单。

  第(2)种方式,由于兴叫蒸望表要涉及到线程的同步,有可能会面临死锁等问题。

小常加各候游放维布  第(3)种方式,在写应用程序代码时,逻辑比前致均乡修志多陈也谓史面两种都复杂。

  综合考虑各方面因素,一般普遍认为第(3)种方式是大多数网络服务器采用的方式,这也是本文讨论的重点-事件驱动处理库。

select

  selec否助矿念功切挥脚展象女t在linux和windows平台上都支持的,接口基本上相同,但360百科参数的含义略有不同。通常,使用select库的步黑欢认需却将分学骤是:

  (1)创建所关注促实起的事件的描述符集合(fd_set),对于一个细早跟丝裂死粒描述符,可以关注其上面的读(read)、写征别浓滑简染(write)、异常(exception)事件,所以通常,要创建三个fd_set, 一个用来收集关注读事件的描述符,一个用来收口松集关注写事件的描述符,另外一个用来收集关注异常事件的描述符集合。

  (2胶军延准讨降)调用select(),等待事件发生。这里需要注意的一点是,select的阻塞与是否设置非阻塞I/O是没有关系的。sele罗特该脱缺情住ct的原型如下所示:

  int select(int nfds 缺含乙显状跟巴和船喜成,

  fd_se商间生紧模独t* readfds ,

  fd_set* writefds ,

  fd_set* exceptfds,

  const struct timeval* timeout

  其中,最后一个参数timeout,可以设置select觉溶已高待和土视等待的时间。如果该值设置为0,那么,select()在有事件发生的时候就立即返回。如果该值不为0,那么,select()会等待指定的时间,然后再返回。select()的返回值指定了发生事件的fd个数。

  (3)轮询所有fd_set中的每一个fd ,检查是否有相应的事件发生,如果有,就进据旧位庆高刘千全语训行处理。

po来自ll

  poll库是在linux2.1.23中引入的,windows平台不支持poll. poll与select的基本方式相同,都是先创建一个关注事件的描述符的集360百科合,然后再去等待这些事件发生,然后再轮询描述符集合,检查有没有事件发生,如果有,就进行处理。因此,poll有着与select相似的处理流程:

  (1)创建描述符集合,设置关注的事件

  (2)调用poll(),等待事件发生。下面是poll的原型:

  int poll(struct pollfd *fds, nfds_t nfds, int timeout);

带氧场  类似select,poll也可以府评参极盐研设置等待时间,效果与select一样。

  (3)轮询描述七需练里环自呼只弱牛改符集合,检查事件,处理事件。

  在这里要说明的是,poll与select的主要区气连斯政医增模行二着六别在与,select需要为读、杂压写、异常事件分别创建一个描放布协究停钟述符集合,最后轮询的时候,需要分别轮询这三个集合。而poll只需要一个集合,在每个描述符对应的结构上扩华分别设置读、写、异常事件,最后轮询的时候,可以同时检查三种事件

epoll

  epoll是和上面的poll和sele药类功ct不同的一个事件驱动库,它是在linux 2.5.44中引入的,它属于poll的一个变种。上面的poll和select库,它们的最大的问市级绿题就在于效率。它们的处理方式都是创建一个事件列表,然后把这个列表发给内核,返回的时候,再去轮询检查这个列表套始开带片质各屋去烈获,这样在描述符比较多的应用中,效率就显得比较低下了。一种比较好的做法是,把描述符列表交给内核,一旦有事件发生,内核把发生事件的描述符列表通知给进程,这样就避免了轮询整个描述符列表。e坏集拿绝游比认poll就是这样一种模型。下面对epoll的使用进行说明:

  (1).创建一个副病定苏探epoll描述符,调用epol全关l_create()来完成,epoll_create()有一个整型死的陆住丰责的参数size,用来告诉内核,要创建一个有size个描述符的事件列表(集合)

  int e而众村乱poll_create(int size)

  (新喜操零否马还管预首2).给描述符设置所关注的事件,并把它添加到内核的事件列表中去,这里需要调用epoll_ctl()来完成。

  int epoll_ctl(int epfd, int o然妒约p, int fd, struct epoll_event *event)

  这里op参数有三种,分别代表三种操作:

  a. EPOLL_CTL_ADD, 把要关注的描述符和对其关注的事件的结构,添加到内核的事件列表中去

  b. EPOLL_CTL_DEL,把先前添加的描述符和对其关注的事件的结构,从内核的事件列表中去除

  c. EPOLL_CTL_MOD,修改先前添加到内核的事件列表中的描述符的关注的事件

  (3). 等待内核通知事件发生,得到发生事件的描述符的结构列表,该过程由epoll_wait()完成。得到事件列表后,就可以进行事件处理了。

  int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)

  在使用epoll的时候,有一个需要特别注意的地方,那就是epoll触发事件的文件有两种方式:

  (1)Edge Triggered(ET),在这种情况下,事件是由数据到达边界触发的。所以要在处理读、写的时候,要不断的调用read/write,直到它们返回EAGAIN,然后再去epoll_wait(),等待下次事件的发生。这种方式适用要遵从下面的原则:

  a. 使用非阻塞的I/O;b.直到read/write返回EAGAIN时,才去等待下一次事件的发生。

  (2)Level Triggered(LT), 在这种情况下,epoll和poll类似,但处理速度上可能比poll快。在这种情况下,只要有数据没有读、写完,调用epoll_wait()的时候,就会有事件被触发。

转载请注明出处累积网 » 事件驱动模型

相关推荐

    声明:此文信息来源于网络,登载此文只为提供信息参考,并不用于任何商业目的。如有侵权,请及时联系我们:fendou3451@163.com