I/O多路复用

news/2024/4/29 0:30:24/文章来源:https://blog.csdn.net/xs925048899/article/details/128954263

基础概念

Socket

套接字。百科:对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。

例子1:客户端将数据通过网线发送到服务端,客户端发送数据需要一个出口,服务端接收数据需要一个入口,这两个“口子”就是 Socket。

例子2:两个人通过电话进行通信,两个人都需要持有1个电话,socket 就类似于这个电话。

FD:file descriptor

文件描述符,非负整数。“一切皆文件”,linux 中的一切资源都可以通过文件的方式访问和管理。而 FD 就类似文件的索引(符号、指针),指向某个资源,内核(kernel)利用 FD 来访问和管理资源。

之前在视频中有同学问既然有 socket,为什么文章内容全是用的 FD 来举例,这是因为当我们调用内核函数创建 socket 后,内核返回给我们的是 socket 对应的文件描述符(fd),所以我们对 socket 的操作基本都是通过 fd 来进行。

阻塞IO

服务端为了处理客户端的连接和请求的数据,写了如下代码。这段代码会执行得磕磕绊绊。
在这里插入图片描述

可以看到,服务端的线程阻塞在了两个地方,一个是 accept 函数,一个是 read 函数。
如果这个连接的客户端一直不发数据,那么服务端线程将会一直阻塞在 read 函数上不返回,也无法接受其他客户端连接。

非阻塞 IO

为了解决上面的问题,其关键在于改造这个 read 函数。

有一种聪明的办法是,每次都创建一个新的进程或线程,去调用 read 函数,并做业务处理。

在这里插入图片描述
这样,当给一个客户端建立好连接后,就可以立刻等待新的客户端连接,而不用阻塞在原客户端的 read 请求上

不过,这不叫非阻塞 IO,只不过用了多线程的手段使得主线程没有卡在 read 函数上不往下走罢了。操作系统为我们提供的 read 函数仍然是阻塞的。

所以真正的非阻塞 IO,不能是通过我们用户层的小把戏,而是要恳请操作系统为我们提供一个非阻塞的 read 函数。

这个 read 函数的效果是,如果没有数据到达时(到达网卡并拷贝到了内核缓冲区),立刻返回一个错误值(-1),而不是阻塞地等待。

操作系统提供了这样的功能,只需要在调用 read 前,将文件描述符设置为非阻塞即可。

IO 多路复用

为每个客户端创建一个线程,服务器端的线程资源很容易被耗光。
在这里插入图片描述
当然还有个聪明的办法,我们可以每 accept 一个客户端连接后,将这个文件描述符(connfd)放到一个数组里。

然后弄一个新的线程去不断遍历这个数组,调用每一个元素的非阻塞 read 方法。

这样,我们就成功用一个线程处理了多个客户端连接。

但这和我们用多线程去将阻塞 IO 改造成看起来是非阻塞 IO 一样,这种遍历方式也只是我们用户自己想出的小把戏,每次遍历遇到 read 返回 -1 时仍然是一次浪费资源的系统调用。
在这里插入图片描述

所以,还是得恳请操作系统老大,提供给我们一个有这样效果的函数,我们将一批文件描述符通过一次系统调用传给内核,由内核层去遍历(而不是在用户态调用,再陷入到内核态中去遍历),才能真正解决这个问题。

select

select 是操作系统提供的系统调用函数,通过它,我们可以把一个文件描述符的数组发给操作系统, 让操作系统去遍历,确定哪个文件描述符可以读写, 然后告诉我们去处理:
在这里插入图片描述
select的问题:

  • select 调用需要传入 fd 数组,需要拷贝一份到内核,高并发场景下这样的拷贝消耗的资源是惊人的。(可优化为不复制)
  • select 在内核层仍然是通过遍历的方式检查文件描述符的就绪状态,是个同步过程,只不过无系统调用切换上下文的开销。(内核层可优化为异步事件通知)
  • select 仅仅返回可读文件描述符的个数,具体哪个可读还是要用户自己遍历。(可优化为只返回给用户就绪的文件描述符,无需用户做无效的遍历)

epoll

epoll 是最终的大 boss,它解决了 select 和 poll 的一些问题。
epoll 主要就是针对上面三个缺点进行了改进。

  • 内核中保存一份文件描述符集合,无需用户每次都重新传入,只需告诉内核修改的部分即可。
  • 内核不再通过轮询的方式找到就绪的文件描述符,而是通过异步 IO 事件唤醒。
  • 内核仅会将有 IO 事件的文件描述符返回给用户,用户也无需遍历整个文件描述符集合。

使用起来,其内部原理就像如下一般丝滑。
在这里插入图片描述

IO模型小例子

例子:你是一个老师,让学生做作业,学生做完作业后收作业。

同步阻塞:逐个收作业,先收A,再收B,接着是C、D,如果有一个学生还未做完,则你会等到他写完,然后才继续收下一个。

解析:这就是同步阻塞的特点,只要中间有一个未就绪,则你会被阻塞住,从而影响到后面的其他学生。

同步非阻塞:逐个收作业,先收A,再收B,接着是C、D,如果有一个学生还未做完,则你会跳过该学生,继续去收下一个。

解析:可以看到同步非阻塞相较于同步阻塞已经是更好的方案了,你不会因为某个学生未就绪而阻塞住,这样就可以减少对后续学生的影响。但是这个方案也可能会出现其他问题,如果你下去收作业的时候,全部学生都还没做完,则你可能会白走一圈,然后一个作业也没收到。

select/poll:学生写完了作业会举手,但是你不知道是谁举手,需要一个个的去询问。

解析:这个方案相较于同步非阻塞来说有一点好处,就是你是确认有学生做完的,所以你下去肯定能收到作业,但是他有一个不好的点在于你需要一个个的去询问。

epoll:学生写完了作业会举手,你知道是谁举手,你直接去收作业。

解析:这个方案就很高效了,每次都能准确的收到作业。

总结

一切的开始,都起源于这个 read 函数是操作系统提供的,而且是阻塞的,我们叫它 阻塞 IO

为了破这个局,程序员在用户态通过多线程来防止主线程卡死。

后来操作系统发现这个需求比较大,于是在操作系统层面提供了非阻塞的 read 函数,这样程序员就可以在一个线程内完成多个文件描述符的读取,这就是 非阻塞 IO

但多个文件描述符的读取就需要遍历,当高并发场景越来越多时,用户态遍历的文件描述符也越来越多,相当于在 while 循环里进行了越来越多的系统调用。

后来操作系统又发现这个场景需求量较大,于是又在操作系统层面提供了这样的遍历文件描述符的机制,这就是 IO 多路复用

多路复用有三个函数,最开始是 select,然后又发明了 poll 解决了 select 文件描述符的限制,然后又发明了 epoll 解决 select 的三个不足。

所以,IO 模型的演进,其实就是时代的变化,倒逼着操作系统将更多的功能加到自己的内核而已。

如果你建立了这样的思维,很容易发现网上的一些错误。

比如好多文章说,多路复用之所以效率高,是因为用一个线程就可以监控多个文件描述符。

这显然是知其然而不知其所以然,多路复用产生的效果,完全可以由用户态去遍历文件描述符并调用其非阻塞的 read 函数实现。而多路复用快的原因在于,操作系统提供了这样的系统调用,使得原来的 while 循环里多次系统调用,变成了一次系统调用 + 内核层遍历这些文件描述符。

就好比我们平时写业务代码,把原来 while 循环里调 http 接口进行批量,改成了让对方提供一个批量添加的 http 接口,然后我们一次 rpc 请求就完成了批量添加。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_255852.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开发技术-Java switch case 的简单用法

文章目录1. integral-selector2. case3. break4. default5. 总结最近开发写 switch 发现有的技术点还没有掌握,在此做个记录。ON JAVA 中文版中,关于 switch 的描述为: switch 有时也被划归为一种选择语句。根据整数表达式的值,s…

数据挖掘,计算机网络、操作系统刷题笔记47

数据挖掘,计算机网络、操作系统刷题笔记47 2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得去找开发,测开 测开的话,你就得学数据库,sql,orac…

FFmpeg集成qsv的编译安装

文章目录FFmpeg集成qsv的编译安装一、参考二、编译安装流程1. LibVA 和 Media-Driver 的安装2. Intel Media SDK 编译3. ffmpeg的编译安装4. 验证安装FFmpeg集成qsv的编译安装 一、参考 Ubuntu20.04 ffmpeg添加 Intel核显QSV加速支持 视频和视频帧:Intel GPU&…

持续集成Jenkins (四)Jenkins+git+maven项目构建、自动化部署

GIT配置1.1 前言:需要安装 git 客户端.yum install git1.2 Jenkins 配置插件 Git 在仪表盘选择Manage Jenkins>>Plugin Manager>>进入如下页面,可以选择可选的插件,安装完成后的插件在installed里面可以看到,我这里已…

Conda安装到虚拟环境中的包在pycharm中不显示--pip下载的包都到了base环境中-Ubuntu20.04

问题 今天刚装了一个Ubuntu20.04系统,安装完Anaconda,虚拟环境的包也都下载好了,结果在pycharm中配置完解释器后,只有几个基础的包,切换到base环境后发现,这些包都被下载到了base环境中。 在网上查了各种…

安装PhpStorm2020.3

1、卸载旧软件 如果已安装软件,先打开文件安装目录,找到Uninstall.exe点击卸载 删除.jetbrains目录 点击软件“PhpStorm-2020.3.exe”安装 打开软件 打开一个新建的空文件夹,预加载 将BetterIntelliJ.zip拖动到idea的编辑区域 然后…

我们的微服务中为什么需要网关?

说起 Spring Cloud Gateway 的使用场景,我相信很多小伙伴都能够脱口而出认证二字,确实,在网关中完成认证操作,确实是 Gateway 的重要使用场景之一,然而并不是唯一的使用场景。在微服务中使用网关的好处可太多了&#x…

nodejs基于vue的饭店点餐外卖平台网站

本系统主要实现了管理员:首页、个人中心、用户管理、菜品分类管理、菜品信息管理、菜品评价管理、系统管理、订单管理,用户:首页、个人中心、菜品评价管理、我的收藏管理、订单管理,前台首页:首页、菜品信息、菜品资讯、个人中心、后台管理、…

C++——继承那些事儿你真的知道吗?

目录1.继承的概念及定义1.1继承的概念1.2 继承定义1.2.1定义格式1.2.2继承关系和访问限定符1.2.3继承基类成员访问方式的变化2.父类和子类对象赋值转换3.继承中的作用域4.派生类的默认成员函数5.继承与友元6. 继承与静态成员7.复杂的菱形继承及菱形虚拟继承如何解决数据冗余和二…

基于深度学习的安全帽监管系统

摘 要 安全生产管理是建筑、重工业等高危企业发展的重要方针,安全帽在施工生产环境中对人员头部防护起着关键作用,因此加强安全帽佩戴监管十分必要。近年来,基于图像视觉的安全帽佩戴监测方法成为了企业实施管理的主要手段,如何提高安全帽佩戴检测精度和检测速度是应用的关键难…

【C++】 类和对象 (下)

文章目录📕再谈构造函数1. 构造函数体赋值2. 初始化列表3. explicit 关键字📕static 成员1. 概念2. static 成员变量3. static 成员函数📕 友元1. 友元函数2. 友元类📕内部类📕编译器优化📕再谈构造函数 1…

C# 引用DLL 静态字段和非静态字段

再讲一下如何引用dll动态链接库:右键项目----添加 --项目引用----选择你要添加的dll即可。在依赖项这里就可以看到。再在要用的项目那里using一下这个dll的命名空间:using 生成dll;然后就可以使用以下所说的两种方法去调用dll里的函数了。切记&#xff0…

canal 使用详解

第1章 Canal 简介canal [kənl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费工作原理canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送 d…

fastadmin后台表单文字过长,限制显示,鼠标悬停显示全部

问题&#xff1a;显示文字区域过长&#xff0c;影响用户体验感 解决措施&#xff1a; 特别注意&#xff1a; return "<span styledisplay: block;overflow: hidden;text-overflow: ellipsis;white-space: nowrap; title" row.contents ">" value …

【物联网平台选型】葵花宝典:盘点开源、SaaS及通用型平台的优劣势和选型适配

随着工业物联网领域和智慧物联领域的发展&#xff0c;大大小小的物联项目和物联场景需求层出不穷&#xff0c;物联网平台作为技术底座型软件&#xff0c;是不可或缺的项目地基。 市场需求下&#xff0c;物联网平台提供商越来越多&#xff0c;“打地基”的方式大体分为开源平台、…

内核数据结构-XArray

内核数据结构-XArrayXArray简介XArray 基本数据结构Xarray结构图API介绍Xarray锁参考链接XArray简介 XArray是一种抽象数据类型&#xff0c;类似于一个大的指针数组&#xff0c;它满足了许多与哈希或常规可调整大小数组相同的需求。由于 xarray 中的数据都是指针&#xff0c;使…

以太网知识-GMII / RGMII接口

今天和海翎光电的小编一起分析MII/RMII/SMII&#xff0c;以及GMII/RGMII/SGMII接口的信号定义&#xff0c;及相关知识&#xff0c;同时小编也对RJ-45接口进行了总结&#xff0c;分析了在10/100模式下和1000M模式下的连接方法。GMII 接口分析GMII接口提供了8位数据通道&#xff…

shell条件测试

文章目录三、shell条件测试3.1条件测试的基本语法3.2 文件测试表达式3.3字符串测试表达式3.4 整数测试表达式3.5 逻辑操作符三、shell条件测试 为了能够正确处理Shell程序运行过程中遇到的各种情况&#xff0c;Linux Shell提供了一组测试运算符。通过这些运算符&#xff0c;Sh…

go语言的并发编程

并发编程是 Go语言的一个重要特性,而 go语言也是基于此而设计出来的。 本文将会介绍如何使用go-gc中的“runtime”方法实现 go语言中的并发编程。 在之前的文章中,我们已经对 runtime方法进行了详细介绍,这次文章将对 runtime方法进行深入分析,并讲解如何在go-gc中使用该方…

智能建筑电力监控自动化的解决方案

引言 安科瑞 李亚俊 壹捌柒贰壹零玖捌柒伍柒 所谓智能建筑就是采用计算机技术和通讯技术对建筑的设备进行自动监控&#xff0c;对信息资源进行管理和为用户提供信息服务等。美国智能建筑研究机构把智能建筑定义为&#xff1a;通过对建筑物的结构、系统、服务和管理四个基本要…