完全理解epoll高效操作的原理

                                          完全理解epoll高效操作的原理


                                          更多内容,欢迎关注微信公众号:整碟工程师小慧〜前言这篇文章不明白,没关系,你可以先收集它。作者准备介绍epoll和NIO等知识点,然后编写Java网络IO模型的介绍,可以使Java网络IO的知识系统更加完整和严谨。初学者还可以等待看IO模型引入的博客,然后回顾这些博客,这将更有意义。如果您已成功撰写此博客,恭喜您,nginx,redis和NIO的核心理念已经掌握,您可以扩展您的理解。否则,只要孤立地看看epoll,时间就会很快被遗忘。当然,这些核心思想,作者将在博客中稍后详细解释,欢迎关注epoll的概念是一种I/O事件通知机制,是linux linux IO多路复用的一种实现。 IO多路复用意味着在一次操作中同时监视多个输入和输出源,并且一个或多个输入和输出源在可用时返回,然后进行读写。 IO复用将在未来的博客中详细解释。 I/O输入/输出(对象/输出)对象可以是文件(文件),网络(套接字),进程之间的管道。在Linux系统中,它由文件描述符(fd)表示。当与文件描述符关联的内核读缓冲区可读时触发可读事件的事件可读事件。 (读取:内核缓冲区不为空,可以读取数据)可写事件,当与文件描述符关联的内核写缓冲区可写时,触发可写事件。 (可写:内核缓冲区未满,有可用空间写入)通知机制通知机制,即事件发生时,会通知它。通知机制的反面是轮询机制。 Epoll的流行解释结合了以上三种,epoll的流行解释是一种机制,当文件描述符的内核缓冲区不为空时发送可读信号以通知,并在写入缓冲区未满时发送可写信号。 epoll API详细信息epoll核心是3个API,核心数据结构是:1个红黑树和1个链表epoll1。 int epoll_create(int size)函数:内核将生成一个epoll实例数据结构并返回一个文件描述符这个特殊描述符是epoll实例的句柄,后两个接口以它为中心(即epfd参数)。 size参数指示要监视的文件描述符的最大值,但在Linux的更高版本中已弃用(同时,大小不传递0,它将报告无效参数错误)2。int epoll_ctl(int epfd ,int op,int fd,struct epoll_event * event)function:将截取的描述符添加到红黑树中,或将其从红黑树中删除或修改listen事件。 typedef union epoll_data {void * ptr;/*指向用户定义的数据*/int Fd;/*已注册的文件描述符*/uint32_t u32;/* 32位整数*/uint64_t u64;/* 64位整数* /} epoll_data_t; struct epoll_event {uint32_t events;/*说明epoll事件*/epoll_data_t数据;/*见上面的结构* /};对于要监视的文件描述符集,epoll_ctl管理红黑树,红黑树的每个成员由描述符值和要监视的文件描述符指向。对文件条目等的引用。参数说明操作类型:EPOLL_CTL_ADD:将要监视的描述符添加到兴趣列表中。 EPOLL_CTL_DEL:从兴趣列表中删除描述符。 EPOLL_CTL_MOD:修改兴趣列表中的描述符。 struct epoll_event结构描述了文件描述符的epoll行为。 当使用epoll_wait函数返回就绪状态的描述符列表时,数据字段是唯一可以提供描述符信息的字段,因此在调用epoll_ctl添加要监视的描述符时,请务必在此字段中编写描述符。信息事件字段是描述一组epoll事件的位掩码,其在epoll_ctl调用中被解释为:描述符期望的epoll事件,其可以是多选的。常用的epoll事件描述如下:EPOLLIN:描述符处于可读状态。 EPOLLOUT:描述符处于可写状态。 EPOLLET:将epoll事件通知模式设置为edge triggeredEPOLLONESHOT:第一个通知,然后不再监视EPOLLHUP:本地描述该字符生成挂起事件,默认监视事件EPOLLRDHUP:对等描述符生成挂起事件EPOLLPRI:触发通过带外数据EPOLLERR:当描述符生成错误时触发,默认检测事件3. int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);功能:阻止等待注册的事件,返回事件数,并将触发事件写入事件数组。事件:用于记录触发事件,大小应与maxevents maxevents:一致。就绪状态中返回的最大事件数将复制到就绪列表中,epoll_wait用于将就绪列表返回给用户进程。 events和maxevents参数描述用户分配的struct epoll事件数组。当调用返回时,内核将就绪列表复制到数组中,并使用实际的副本数作为返回值。请注意,如果就绪列表长于maxevents,则只能复制第一个maxevents成员;否则,就绪列表可以完全复制。此外,struct epoll事件结构中的events字段在此解释为:在被监视的文件描述符上发生的实际事件。参数timeout表示函数调用中阻塞时间的上限。单位为ms:timeout=-1表示调用将阻塞,直到文件描述符进入就绪状态或捕获信号。超时=0用于非阻塞检测。描述符处于就绪状态,无论结果如何,调用都会立即返回;超时> 0表示如果检测到的对象准备就绪或捕获到信号,则呼叫将持续最长超时时间,否则将超时。 Epoll的两种触发方法epoll监视多个文件描述符的I/O事件。 Epoll支持边沿触发(ET)或电平触发(LT),通过epoll_wait等待I/O事件,并在当前没有可用事件时阻止调用线程。选择并轮询仅支持LT工作模式,epoll的默认工作模式为LT模式。 1.水平触发的时序对于读操作,只要缓冲区内容不为空,LT模式就会返回read ready。对于写操作,只要缓冲区未满,LT模式就会返回写入就绪。当在受监视的文件描述符上发生读/写事件时,epoll_wait()会通知处理程序进行读取或写入。 如果您不是一次性读取和写入数据(例如读取和写入缓冲区太小),那么下次调用epoll_wait()时,它还会通知您继续读取和写入文件描述符没有读过或写过的。当然,如果您没有阅读或写作,它会通知您。如果系统中有大量就绪文件描述符,您不需要读取或写入,并且每次都会返回,这将大大降低处理程序检索感兴趣的就绪文件描述符的效率。 2.边沿触发的时序是当缓冲区变得不可读并且变得可读时,即当缓冲区从空变为空时的读操作。当有新数据到达时,也就是说,当缓冲区中有更多数据需要读取时。当缓冲区具有数据可读性时,应用程序进程使EPOLL_CTL_MOD修改相应描述符的EPOLLIN事件。对于写入操作,当缓冲区不可写为可写入时。当发送旧数据时,即缓冲区中的内容减少。当缓冲区有空间写入时,应用程序进程使EPOLL_CTL_MOD修改相应描述符的EPOLLOUT事件。当在受监视的文件描述符上发生读/写事件时,epoll_wait()会通知处理程序进行读取或写入。如果你不是一直读取或写入数据(例如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是说,它只会通知你你有一次,直到文件描述符。第二个可读写的事件将通知您。此模式比水平触发更有效,并且系统不会充斥您不关心的大量现成文件描述符。在ET模式下,缓冲区永远不可读和可读,它将唤醒应用程序进程,如果缓冲区数据较少,则应用程序进程不会再次唤醒。 示例1:读缓冲区最初为空,读缓冲区写入2KB数据级。触发和边沿触发模式将发出可读信号。当接收到信号时,读取1KB数据,并且1KB保留在读缓冲器中。将再次通知数据级触发器,并且不会再次通知边沿触发器。例2 :(以脉冲的高低电平为例)水平触发:0表示无数据,1表示数据。如果缓冲区有数据,它将始终为1,并且将始终触发。边沿触发:0表示没有数据,1表示数据,只要它在0到1的上升沿触发.JDK不实现边沿触发。 Netty重新实现epoll机制并使用边缘触发。此外,Nginx还使用边缘触发。 JDK默认在Linux中使用了epoll,但是JDK的epoll使用了水平触发,而Netty重新实现了epoll机制。通过边缘触发,netty epoll传输暴露了nio没有的更多配置参数,例如TCP_CORK,SO_REUSEADDR。等等。也像Nginx一样也使用边缘触发。 epoll和select的比较,轮询1.用户模式将文件描述符传递给内核选择:创建三个文件描述符集并将它们复制到内核中,分别监听读,写和异常动作。这受到单个进程可以打开的fd数量的限制。默认值为1024.轮询:将传入的struct pollfd结构数组复制到内核中进行监听。 Epoll:执行epoll_create将在内核的高速缓存区域中创建一个红黑树和一个就绪列表(该列表存储准备好的文件描述符)。然后,用户执行的epoll_ctl函数添加文件描述符以将相应的节点添加到红黑树。 2.内核模式检测文件描述符的读写状态。 select:轮询所有fd,最后返回掩码掩码,以确定描述符读写操作是否准备就绪。根据此掩码分配fd_set。轮询:还有轮询模式,查询每个fd的状态,如果准备就绪,在等待队列中添加一个项目并继续遍历。 Epoll:使用回调机制。当执行epoll_ctl的添加操作时,不仅文件描述符被放置在红黑树上,而且还注册了回调函数。当内核检测到文件描述符是可读/可写的时,将调用回调函数,并且回调函数将文件描述符放在就绪列表中。 3.找到就绪文件描述符并将其传递给用户模式。 select:将先前传递的fd_set副本传递给用户状态,并返回就绪文件描述符的总数。用户模式不知道哪些文件描述符处于就绪状态,需要遍历以确定。轮询:将先前传递的fd数组的副本传递出用户状态,并返回就绪文件描述符的总数。用户模式不知道哪些文件描述符处于就绪状态,需要遍历以确定。 Epoll:epoll_wait只需要观察就绪列表中的数据,最后将链表的数据返回给数组并返回就绪数量。内核将就绪文件描述符放在传入数组中,因此只能通过遍历处理它。此处返回的文件描述符通过mmap传递,以允许内核和用户空间共享相同的内存实现,从而减少不必要的副本。 4.重复监听器处理选择:将新的监听器文件描述符集复制到内核中并继续上述步骤。轮询:将新的struct pollfd结构数组的副本传递到内核中,然后继续执行上述步骤。 Epoll:您不需要重建红黑树,只需使用现有的红树。 Epoll效率更高。 select和poll的原因基本相同,只是poll使用链表来存储文件描述符,select选择使用fd来存储位,因此select将受最大连接数的限制,而poll不会。选择,轮询和epoll将返回就绪文件描述符的数量。但是select和poll没有明确指出哪些文件描述符已经准备就绪,而epoll会这样做。不同之处在于系统调用返回后,调用select和poll的程序需要遍历监听器的整个文件描述符,以找出谁准备好了,epoll可以直接处理它。选择,poll需要将文件描述符的数据结构复制到内核中,最后复制它。 epoll自身创建的文件描述符的数据结构存储在内核状态中。当系统调用返回时,mmap()文件用于映射内存加速和内核空间消息传递:也就是说,epoll使用mmap来减少复制开销。选择,轮询使用轮询来检查文件描述符是否处于就绪状态,epoll使用回调机制。结果是,随着fd增加,select和poll的效率将线性降低,epoll不会受到太大影响,除非有许多活动套接字。 Epoll的边缘触发模式是高效的,系统不会泛滥很多不关心的现成文件描述符。尽管epoll具有最佳性能,但当连接数量较少且连接非常活跃时,select和poll的性能可能优于epoll。毕竟,epoll的通知机制需要大量的函数回调。更多内容,欢迎关注微信公众号:整个菜工程师小慧〜

                                          上一篇:Facebook为阻止美国货币,挑战美元霸权将引发全球货币战争

                                          下一篇:专家云整合,共有“智能+”时代的新机遇

                                          相关推荐:韩景帝与韩文帝之间的差距,高世烈的案例 | 厄尔尼诺现象对海洋热量预算的研究取得了进展 | 阅读:人,知道差异,知道如何改变位置

                                          评论

                                          您的邮箱地址不会被公布 *

                                          您可以使用这些html标签 <a href="#" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>