一文搞懂select、poll和epoll区别

简介: 一文搞懂select、poll和epoll区别

「操作系统在处理 io 的时候,主要有两个阶段:」

  • 等待数据传到 io 设备
  • io 设备将数据复制到 user space

我们一般将上述过程简化理解为:

  • 等到数据传到 kernel 内核 space
  • kernel 内核区域将数据复制到 user space(理解为进程或者线程的缓冲区)

select,poll,epoll 都是 IO 多路复用的机制。I/O 多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但 select,poll,epoll 本质上都是同步 I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步 I/O 则无需自己负责进行读写,异步 I/O 的实现会负责把数据从内核拷贝到用户空间。

select

单个进程就可以同时处理多个网络连接的 io 请求(同时阻塞多个 io 操作)。基本原理就是程序呼叫 select,然后整个程序就阻塞状态,这时候,kernel 内核就会轮询检查所有 select 负责的文件描述符 fd,当找到其中那个的数据准备好了文件描述符,会返回给 select,select 通知系统调用,将数据从 kernel 内核复制到进程缓冲区(用户空间)。

640.png

下图为 select 同时从多个客户端接受数据的过程

虽然服务器进程会被 select 阻塞,但是 select 会利用内核不断轮询监听其他客户端的 io 操作是否完成

640.png

select 的几大缺点:

(1)每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大

(2)同时每次调用 select 都需要在内核遍历传递进来的所有 fd,这个开销在 fd 很多时也很大

(3)select 支持的文件描述符数量太小了,默认是 1024

Poll 介绍

poll 的原理与 select 非常相似,差别如下:

  • 描述 fd 集合的方式不同,poll 使用 pollfd 结构而不是 select 结构 fd_set 结构,所以 poll 是链式的,没有最大连接数的限制
  • poll 有一个特点是水平触发,也就是通知程序 fd 就绪后,这次没有被处理,那么下次 poll 的时候会再次通知同个 fd 已经就绪。

select 的几大缺点:

(1)每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大

(2)同时每次调用 select 都需要在内核遍历传递进来的所有 fd,这个开销在 fd 很多时也很大

(3)select 支持的文件描述符数量太小了,默认是 1024

细谈事件驱动-->epoll

epoll 提供了三个函数:

  • int epoll_create(int size); 建立一個 epoll 对象,并传回它的 id
  • int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 事件注册函数,将需要监听的事件和需要监听的 fd 交给 epoll 对象
  • int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);等待注册的事件被触发或者 timeout 发生

epoll 解决的问题:

  • epoll 没有 fd 数量限制 epoll 没有这个限制,我们知道每个 epoll 监听一个 fd,所以最大数量与能打开的 fd 数量有关,一个 g 的内存的机器上,能打开 10 万个左右
  • epoll 不需要每次都从用户空间将 fd_set 复制到内核 kernel epoll 在用 epoll_ctl 函数进行事件注册的时候,已经将 fd 复制到内核中,所以不需要每次都重新复制一次
  • select 和 poll 都是主动轮询机制,需要遍历每一个人 fd;epoll 是被动触发方式,给 fd 注册了相应事件的时候,我们为每一个 fd 指定了一个回调函数,当数据准备好之后,就会把就绪的 fd 加入一个就绪的队列中,epoll_wait 的工作方式实际上就是在这个就绪队列中查看有没有就绪的 fd,如果有,就唤醒就绪队列上的等待者,然后调用回调函数。
  • 虽然 epoll。poll。epoll 都需要查看是否有 fd 就绪,但是 epoll 之所以是被动触发,就在于它只要去查找就绪队列中有没有 fd,就绪的 fd 是主动加到队列中,epoll 不需要一个个轮询确认。换一句话讲,就是 select 和 poll 只能通知有 fd 已经就绪了,但不能知道究竟是哪个 fd 就绪,所以 select 和 poll 就要去主动轮询一遍找到就绪的 fd。而 epoll 则是不但可以知道有 fd 可以就绪,而且还具体可以知道就绪 fd 的编号,所以直接找到就可以,不用轮询。

总结

select, poll 是为了解決同时大量 IO 的情況(尤其网络服务器),但是随着连接数越多,性能越差 epoll 是 select 和 poll 的改进方案,在 linux 上可以取代 select 和 poll,可以处理大量连接的性能问题


相关文章
|
监控 网络协议 Linux
彻底解密:select,poll底层系统调用的核心思想原理
彻底解密:select,poll底层系统调用的核心思想原理
|
5月前
|
存储 Java Linux
详细地说一说零拷贝
我是小假 期待与你的下一次相遇 ~
301 1
详细地说一说零拷贝
|
7月前
|
Java 关系型数据库 MySQL
深入解析 @Transactional——Spring 事务管理的核心
本文深入解析了 Spring Boot 中 `@Transactional` 的工作机制、常见陷阱及最佳实践。作为事务管理的核心注解,`@Transactional` 确保数据库操作的原子性,避免数据不一致问题。文章通过示例讲解了其基本用法、默认回滚规则(仅未捕获的运行时异常触发回滚)、因 `try-catch` 或方法访问修饰符不当导致失效的情况,以及数据库引擎对事务的支持要求。最后总结了使用 `@Transactional` 的五大最佳实践,帮助开发者规避常见问题,提升项目稳定性与可靠性。
1204 12
|
NoSQL Redis
Redis 执行 Lua保证原子性原理
Redis 执行 Lua 保证原子性原理
979 1
|
安全 调度
什么是用户态和内核态?
【10月更文挑战第29天】用户态和内核态是操作系统中两个不同的运行级别和权限状态,它们相互配合,共同构成了操作系统的运行基础,为计算机系统的稳定运行和应用程序的高效执行提供了保障。
1341 31
|
监控 网络协议 Java
IO 多路复用? 什么是 IO 多路复用? 简单示例(日常生活)来解释 IO 多路复用 一看就懂! 大白话,可爱式(傻瓜式)教学! 保你懂!
本文通过日常生活中的简单示例解释了IO多路复用的概念,即一个线程通过监控多个socket来处理多个客户端请求,提高了效率,同时介绍了Linux系统中的select、poll和epoll三种IO多路复用的API。
808 2
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
3182 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
消息中间件 存储 SQL
Kafka架构及其原理
Kafka架构及其原理
1093 1
|
消息中间件 调度 RocketMQ
【RocketMQ系列六】RocketMQ事务消息
【RocketMQ系列六】RocketMQ事务消息
3080 1
|
消息中间件 设计模式 安全
深入理解AQS队列同步器原理-从ReentrantLock的非公平独占锁实现来看AQS的原理
深入理解AQS队列同步器原理-从ReentrantLock的非公平独占锁实现来看AQS的原理
下一篇
oss云网关配置