epoll使用与原理

epoll · 浏览次数 : 9

小编点评

本文主要讨论了Linux中的epoll事件分发接口,它可以同时作为边缘触发(ET)和水平触发(LT)使用。两种模式的区别在于事件触发的方式和时机。 1. 边缘触发(ET)模式:在这种模式下,内核只会报告文件描述符上的变化。也就是说,只有当监控的文件描述符发生更改时,内核才会上报事件。这就可能导致在一个空闲的read调用中,内核可能不会立即返回数据,即使文件描述符仍然可读。 例子:假设正在使用管道(pipe)进行通信,当管道写入端写入数据时,epoll_wait可能会等待,直到有新的数据可读。此时,管道读取端已经读取了一些数据,但epoll_wait仍然会等待,因为边缘触发模式要求在发生变化时才上报事件。 2. 水平触发(LT)模式:在这种模式下,内核会在读/写操作完成后上报事件。这意味着,即使文件描述符已经可读或可写,只要没有到达文件的末尾,epoll_wait仍然会返回事件。这可以避免在空闲的read调用中挂起。 例子:同样使用上述管道通信的例子,在读取端读取1 kB数据后,epoll_wait可能会立即返回新的数据可用,因为它已经到达文件的末端。 在实际应用中,ET模式通常用于需要精确控制事件触发的场景,如键盘输入等。而LT模式适用于大多数I/O密集型应用程序,可以提高性能。同时,了解饥饿问题和解决方案可以帮助开发者在实际应用中更好地利用epoll。 最后,文中提到的解决方法主要是为了防止某个文件描述符在大量数据写入时导致其他文件描述符长时间等待。例如,可以通过限制每个文件描述符一次读取的字节数来控制切换到其他文件描述符,从而避免饥饿现象。 综上所述,在Linux中,epoll提供了边缘触发和水平触发的两种工作模式。这两种模式的主要区别在于内核是否会在没有数据可读时立即上报事件。了解这些区别有助于开发者根据自己的需求选择合适的模式。

正文

使用要点

边缘模式(ET)与水平模式(LT)区别

下面内容来自linux man page

The  epoll event distribution interface is able to behave both as edge-triggered (ET) and as level-triggered (LT).  The difference between he two mechanisms can be described as follows.  Suppose that this scenario happens:
       1. The file descriptor that represents the read side of a pipe (rfd) is registered on the epoll instance.
       2. A pipe writer writes 2 kB of data on the write side of the pipe.
       3. A call to epoll_wait(2) is done that will return rfd as a ready file descriptor.
       4. The pipe reader reads 1 kB of data from rfd.
       5. A call to epoll_wait(2) is done.

       If the rfd file descriptor has been added to the epoll interface using the EPOLLET (edge-triggered) flag, the call to  epoll_wait(2)  done in step 5 will probably hang despite the available data still present in the file input buffer; meanwhile the remote peer might be expecting a response based on the data it already sent.  The reason for this is that edge-triggered mode delivers events only when changes occur on  the  monitored  file descriptor.  So, in step 5 the caller might end up waiting for some data that is already present inside the input buffer.  In the above example, an event on rfd will be generated because of the write done in 2 and the event is consumed in 3.  Since theread operation done in 4 does not consume the whole buffer data, the call to epoll_wait(2) done in step 5 might block indefinitely.

简单来说,如果使用ET模式,对于同一个事件,内核只会上报一次。如果代码没有读取完所有可读取的数据,然后继续调用epoll_wait那么是不会收到事件的。ET模式一般要设定成setnonblocking模式,并且等到读取数据返回EAGAIN或者

如果使用LT模式,则调用epoll_wait后会继续有事件触发。LT模式与poll保持一样的语义,区别是比poll的性能更好一些。

读取数据要点

  • 对于流式连接,例如pipe、fifo、tcp等,通过判定read的返回值比指定读取的小,来判断缓冲区中的数据已经读完了
  • 对于数据报,例如udp等,则通常需要需要持续读取到EAGAIN返回,才能判断缓冲区数据已经读完了
  • 每次从epoll_wait返回后都需要调用epoll_ctl往epoll中继续增加事件

惊群问题解决

  • EPOLLEXCLUSIVE 当多个fd指向同一个文件,并且都被添加到epoll中,那么就可能产生惊群问题:一旦这个文件有被写入,那么read事件会触发给多个fd。加了这个标志后,保证至少一个能收到事件。

ET模式下的饥饿现象

某一个文件,可能来的数据非常多,持续的多,那么这个文件会不停的进行read(按照我们前面说的返回EAGAN或者返回小于指定大小的思路)。由于整个运行时单线程的,那么其他fd就会一直等待,造成了所谓的饥饿现象

epoll的饥饿模式如何避免?linux man page中给出的答案时,不直接在epoll_wait返回后直接读取数据,而是将可读的fd放到一个list里面。然后再对这个list中的fd分别执行read,可以通过限制每个fd一次read的字节数来控制切换到其他fd,当一个fd 读完后从list删除掉。

处理使用 epoll ET 模式下文件描述符出现饥饿的情况_epoll wait防饥饿-CSDN博客

句柄数限制

/proc/sys/fs/epoll/max_user_watches 中记录系统范围内,限制加入到epoll中的句柄数,实际上是限制句柄相关的内存(64位下160字节,32位下90字节)最多只能占用内存的4%。

内核实现原理

epoll_wait是如何实现的

  • 用户调用epoll_wait,会通过syscall指令执行系统调用
  • 系统调用统一入口根据系统调用号走到内核对应的sys_epoll_wait处理函数(内核用call指令 执行)
  • 然后回判断epoolfd里面关联的文件句柄是否有可读的句柄
  • 如果暂时没有那么epoll_wait线程就会等待在这些句柄的queue上
  • 一旦这些文件句柄(例如socket),有数据进来后,内核的ksoftirqd线程会尝试唤醒线程,并从上次线程切换的位置宠幸执行sys_epoll_wait

注意:

  • epoll_ctl会将epollfd加入到io句柄的等待队列中

参考资料

与epoll使用与原理相似的内容:

epoll使用与原理

使用要点 边缘模式(ET)与水平模式(LT)区别 下面内容来自linux man page The epoll event distribution interface is able to behave both as edge-triggered (ET) and as level-trigge

高性能网络设计秘笈:深入剖析Linux网络IO与epoll

本文介绍了网络IO模型,引入了epoll作为Linux系统中高性能网络编程的核心工具。通过分析epoll的特点与优势,并给出使用epoll的注意事项和实践技巧,该文章为读者提供了宝贵的指导。

[转帖]Kafka 核心技术与实战学习笔记(六)kafka线上集群部署方案

一.操作系统-Linux Kafka是JVM系的大数据框架kafka由Scala语言和Java语言编写而成,编译之后的源代码就是普通的".class"文件 使用Linux kafka客户端底层使用Java的selector,selector在Linux上的实现机制是epoll,由于在windows上

[转帖]一文浅析Nginx线程池!

https://zhuanlan.zhihu.com/p/616500765 Nginx通过使用多路复用IO(如Linux的epoll、FreeBSD的kqueue等)技术很好的解决了c10k问题,但前提是Nginx的请求不能有阻塞操作,否则将会导致整个Nginx进程停止服务。 但很多时候阻塞操作是

[转帖]总结:Tomcat的IO模型

一、介绍 对于 linux 操作系统,IO 多路复用使用的是 epoll 方式,对于 windows 操作系统中 IO 多路复用使用的是 iocp 方式,对于 mac 操作系统 IO 多路复用使用的是 kqueue 方式。 由于对于 tomcat 服务器来说基本主要部署在 linux 操作系统上,所

模拟epoll的饥饿场景

说明 一直听说epoll的饥饿场景,但是从未在实际环境中面对过,那么能不能模拟出来呢?实际的情况是怎样呢? 模拟步骤 基于epoll写一个简单的tcp echo server,将每次read返回的字节数打印出来 模拟一个客户端大量写入 测试其他客户端能否正常返回 Server代码 #include

[转帖]精华总结:10个问题理解 Linux epoll

epoll 是 linux 特有的一个 I/O 事件通知机制。很久以来对 epoll 如何能够高效处理数以百万记的文件描述符很有兴趣。近期学习、研究了 epoll 源码,在这个过程中关于 epoll 数据结构和作者的实现思路产生出不少疑惑,在此总结为了 10 个问题并逐个加以解答和分析。 本文基于的

[转帖]图解epoll

图解epoll 本文包含以下内容: epoll是如何工作的 本文不包含以下内容: epoll 的用法 epoll 的缺陷 select 和 poll 的缺点 epoll 对于动辄需要处理上万连接的网络服务应用的意义可以说是革命性的。对于普通的本地应用,select 和 poll可能就很好用了,但对于

[转帖]技术派-epoll和IOCP之比较

直入正题 Epoll 用于Linux系统; IOCP 是用于 Windows; Epoll 是当事件资源满足时发出可处理通知消息; IOCP 则是当事件完成时发出完成通知消息。 从应用程序的角度来看, Epoll 本质上来讲是同步非阻塞的; IOCP 本质上来讲则是异步操作; 举例说明吧 有一个打印

[转帖]网络编程 Epoll原理和底层机制分析

https://zhuanlan.zhihu.com/p/579839553 同 I/O 多路复用和信号驱动 I/O 一样,Linux 的 epoll(event poll)API 可以检查多个文件 描述符上的 I/O 就绪状态。epoll 是 Linux 下多路复用IO接口 select/poll