1407 字
7 分钟
epoll和select

epoll和select#

epoll机制 epoll是“多路复用“技术最好的实现方案,“多路复用”看到这种专业性的词是不是一头雾水啊,咱们举个例子:正常咱们进行阻塞类型的IO读操作(比如从一个socket中读取数据),是不是都会创建一个单独的线程来监听是否有数据到达,如果没有数据到达则线程进入阻塞状态,有的话则线程就开始读取数据。那假如有20个甚至更多的阻塞IO读操作,是不是需要创建对应个数的线程。这些线程如果大部分都没有可读数据的情况下是不是都处于阻塞状态,这难道不是大大得浪费吗?因此“多路复用“技术就出现了,它的设计理念是:启动一个线程,谁有需要监听IO是否有可读数据到达的操作都可以交给这个线程。这里的“多路”指的就是上面例子中创建的多个线程,“复用”指的就是指用一个线程来进行监听操作。 epoll机制在Android中使用非常的广泛,比如Handler的MessageQueue在没有Message的情况下进入阻塞,以及input事件从systemserver进程传递到app进程,甚至vsyn信号从surfaceflinger传递到app进程都用到了epoll机制。 epoll和select都是在Linux系统上使用的I/O多路复用机制,用于在一个线程中同时监听多个文件描述符(包括套接字)的可读、可写和异常等事件。它们可以用于实现高效的事件驱动的网络编程。

select机制: select是一种阻塞式的I/O多路复用机制。通过select函数,可以指定一组文件描述符,并指定需要监视的事件类型(可读、可写、异常等)。当其中任何一个文件描述符就绪时,select函数将返回,并且可以通过遍历文件描述符集合来确定是哪个文件描述符就绪。 select的缺点是,当需要同时监听大量的文件描述符时,会导致效率低下,因为它采用线性扫描的方式遍历文件描述符集合,每次都需要将整个集合从用户空间复制到内核空间。

epoll机制: epoll是一种高效的I/O多路复用机制,引入了事件驱动的方式,通过epoll_wait函数等待事件的发生。它提供了三个系统调用:epoll_create、epoll_ctl和epoll_wait。 epoll使用内核中的红黑树(或者使用双向链表)来存储大量的文件描述符,并且使用回调机制,只返回就绪的文件描述符,避免了select的线性扫描问题。 epoll支持两种工作模式:边缘触发(Edge-Triggered)和水平触发(Level-Triggered)。 在边缘触发模式下,只有当文件描述符状态从未就绪变为就绪时才会通知, 而在水平触发模式下,只要文件描述符处于就绪状态,就会一直通知。 总体而言,epoll相对于select具有更好的性能和扩展性,特别是在需要同时处理大量并发连接的高性能网络服务器中。它减少了系统调用的次数,提高了事件通知的效率。但是需要注意的是,epoll仅在Linux系统上可用,而select在多个平台上都有支持。

分享一个知识点好的,让我们用一个形象化的比喻来解释epoll和select机制。

想象你是一名调度员,负责管理一个大型的会议室,里面有许多与你对话的人(文件描述符)。你需要同时监听所有人是否有事情要告诉你(事件就绪),并及时作出反应。

select机制的比喻:

select机制就像你站在一个大厅中央,面对着所有人。你需要不停地问每个人:“你有事情要和我说吗?”(轮询所有文件描述符)。 每个人都可以回答“是”或“否”,如果有人回答“是”,你会留意他们,并与他们交流(处理就绪的文件描述符)。 但是,这种方式并不高效,因为你需要不停地询问每个人,即使有些人并没有什么要说的(文件描述符未就绪)。这可能导致你浪费了很多时间和精力。

epoll机制的比喻:

epoll机制就像你在大厅中设置了一个接待台,每个人(文件描述符)在有事情要告诉你时都可以去接待台登记。 你只需要关注接待台上是否有人在等待(等待事件就绪),当有人登记时,你会立即注意到,并与他们交流(处理就绪的文件描述符)。 这种方式更高效,因为你不需要主动询问每个人,而是只关注等待登记的人。这样,你可以将更多的时间和精力用于与有事情要告诉你的人进行交互。

总的来说,select机制是通过轮询的方式逐个询问每个文件描述符的状态,而epoll机制则是通过接待台方式,只关注等待事件就绪的文件描述符。这使得epoll在大规模并发场景下更加高效,减少了不必要的轮询开销

epoll和select
作者
强人自传
发布于
2023-06-12
许可协议
CC BY-NC-SA 4.0