百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

深入理解select、poll和epoll及区别

wptr33 2024-12-14 15:35 15 浏览

首先io复用的概念是解决可以让一个进程同时为多个客户端端提供服务,目前的常用的IO复用模型有三种:select,poll,epoll。在时间复杂度分析,select时间复杂度O(n),poll时间复杂度O(n),epoll时间复杂度O(1);poll本质上和select没有区别,实现方式是一样的,存储方式和数据结构有区别,下边主要讲解epoll和select的区别。

先明确几个概念:

I/O 同步和异步的区别在于:将数据从内核复制到用户空间时,用户进程是否会阻塞

I/O 阻塞和非阻塞的区别在于:进程发起系统调用后,是会被挂起直到收到数据后在返回、还是立即返回成功或错误

系统为每一个进程维护了一个文件描述符表,表示该进程打开文件的记录表,而文件描述符实际上就是这张表的索引。当进程打开(open)或者新建(create)文件时,内核会在该进程的文件列表中新增一个表项,同时返回一个文件描述符 —— 也就是新增表项的下标

socket 包含地址、类型和通信协议等信息,就是对底层的封装屏蔽底层tcp/udp fd的创建连接过程,返回一个连接或者fd;进程间通信规则的高层抽象,而 fd 提供的是底层的具体实现,socket 通信,实际上就是通过文件描述符 fd 读写文件。这也符合 Unix“一切皆文件”的哲学。


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

select实现如下图,

int select(
    int nfds,
    fd_set * restrict readfds,
    fd_set * restrict writefds,
    fd_set * restrict errorfds,
    struct timeval * restrict timeout
);

readfds、writefds、errorfds 是三个文件描述符集合。select 会遍历每个集合的前 nfds 个描述符,分别找到可以读取、可以写入、发生错误的描述符,统称为“就绪”的描述符。然后用找到的子集替换参数中的对应集合,返回所有就绪描述符的总数。timeout 参数表示调用 select 时的阻塞时长。fd_set二进制每一位来表示一个文件描述符。某一位为 1,表示对应的文件描述符已就绪。比如比如设 fd_set 长度为 1 字节,则一个 fd_set 变量最大可以表示 8 个文件描述符。当 select 返回 fd_set = 00010011 时,表示文件描述符 125 已经就绪,调用 select 时会陷入内核,这时需要将参数中的 fd_set 从用户空间拷贝到内核空间,内核需要遍历传递进来的所有 fd_set 的每一位(性能开销大),不管它们是否就绪,同时能够监听的文件描述符数量太少(32位1024)。受限于 sizeof(fd_set) 的大小,在编译内核时就确定了且无法更改。一般是 1024,不同的操作系统不相同

epoll 是对 select 和 poll 的改进,避免了“性能开销大”和“文件描述符数量少”两个缺点;epoll 实例内部存储:

监听列表:所有要监听的文件描述符,使用红黑树

就绪列表:所有就绪的文件描述符,使用链表

epoll通过内核和用户空间共享一块内存来实现消息传递,epoll_create 会创建一个 epoll 实例,同时返回一个引用该实例的文件描述符,所以epoll也会占用一个fd,所以在使用完 epoll 后,必须调用 close(epfd) 关闭对应的文件描述符。epoll_ctl 绑定fd指向epoll实例,就是要监听的fd和event,将文件描述符 fd 添加到 epoll 实例的监听列表里,同时为 fd 设置一个回调函数,并监听事件 event。当 fd 上发生相应事件时,会调用回调函数,将 fd 添加到 epoll 实例的就绪队列上。epoll_wait就相当于select,epoll_ctl 中为每个文件描述符指定了回调函数,并在就绪时将其加入到就绪列表,因此 epoll 不需要像 select 那样遍历检测每个文件描述符,只需要判断就绪列表是否为空即可。这样,在没有描述符就绪时,epoll 能更早地让出系统资源

相关推荐

文科生自学Python-生成简单的WORD文档

--天行健君子以自强不息,地势坤君子以厚德载物,学习编程成就更好的自己--Python语言简洁生动,特别适合文科生学习入门IT世界,用几十行代码就能够做一个完整的爬虫脚本,开发效率杠杠的!短时间内即可...

使用Python 爬取京东、淘宝等商品详情页的数据,避开反爬虫机制

以下是爬取京东商品详情的Python3代码,以excel存放链接的方式批量爬取。excel如下...

CV学习笔记(二十四):数据集标注与制作

最近在做一些数据标注的工作,虽然标注数据比较枯燥,但这也是每个做算法的工程师升级打怪的必由之路。使用一些合适的工具往往可以事半功倍,效率UP。一:数据标注流程二:数据处理的一些小代码1:重命名当得到这...

新手常见的python报错及解决方案(如何理解python报错信息)

此篇文章整理新手编写代码常见的一些错误,有些错误是粗心的错误,但对于新手而已,会折腾很长时间才搞定,所以在此总结下我遇到的一些问题。希望帮助到刚入门的朋友们。后续会不断补充。...

殊途同归python第5节:一键管理所有文档

Python自带的os模块,文件和文件夹的小管家,直接上代码importosa=os.getcwd()#获取当前路径,以字符串形式返回当前的绝对路径。os.chdir("动画片收...

1.文件夹的处理 OS(文件夹的操作方法)

os.getcwd()#当前目录os.listdir()#列出目录下的文件os.path.join()#拼接路径os.path.split()#拆分路径os.path.exists...

Linux下分析bin文件的10种方法(linux binary文件)

这世界有10种人,一种人懂二进制,另一种人不懂二进制。——鲁迅大家好,我是良许。二进制文件是我们几乎每天都需要打交道的文件类型,但很少人知道他们的工作原理。这里所讲的二进制文件,是指一些可执行文件,...

文科生自学Python-pandas交叉透视表降维变换

--心有猛虎,细嗅蔷薇,学习编程成就更好的自己--...

史上最全!近万字梳理Python 开发必备的 os 模块(建议收藏)

点赞、收藏、加关注,下次找我不迷路...

工作中必备的12个Git命令(常用git命令清单)

...

Undoing a git rebase(undoing a git rebase)

技术背景在使用Git进行版本控制时,gitrebase是一个强大的命令,它可以将一个分支的修改合并到另一个分支,使提交历史更加线性。然而,在某些情况下,我们可能需要撤销...

【干货】常用的Git命令有哪些?(git 常用命令行入门)

Git是一个开源的分布式版本控制系统,它被广泛用于软件开发中。在使用Git进行版本控制时,有许多常用的命令,本文将对这些命令进行详细的介绍。...

项目中使用 husky 格式化代码和校验 commit 信息

大家好,我是前端西瓜哥。今天我们学习使用husky工具,在commit的时候做一些风格的校验工作,包括commit信息格式化和文件格式化。githook和husky...

Git可视化极简易教程 — Git GUI使用方法

前言...

实际工作中 Git Commit 代码提交规范是什么样的?

...