操作系统 IO 相关知识

news2024/9/23 8:23:03

操作系统 IO 相关知识

  • 阻塞与非阻塞
  • 同步与异步
  • IO 和系统调用
    • 传统的 IO
    • DMA
    • mmap 内存映射
    • sendfile
    • splice
  • 常用的 IO 模型
    • BIO:同步阻塞 IO
    • NIO:同步非阻塞 IO
    • IO 多路复用
    • 信号驱动 IO
    • AIO:异步 IO 模型

IO 就是计算机内部与外部进行数据传输的过程,比如网络 IO 与磁盘 IO

所有 IO 都需要系统调用,由操作系统代理执行,并经历从 IO 设备拷贝到内核空间拷到用户空间的环节

在内核收到调用请求之后,会有数据准备、数据就绪、数据拷贝的阶段

每一个程序员面试的时候或多或少都会被问到相关知识,了解一下相关概念是非常重要的

阻塞与非阻塞

阻塞与非阻塞指线程在等待调用结果(数据,消息,返回值)时的状态

阻塞是指应用线程等待结果时会被挂起,等待内核(或者 IO)完成操作,实际上,内核所做的事情是将 CPU 时间切换给其他有需要的线程,网络应用程序在这种情况下是得不到 CPU 时间做该做的事情的,它会在那里睡觉。因此这里的阻塞应当理解成线程被其他线程阻塞,或者等待 IO 资源结果的时候阻塞

非阻塞是指该线程等待结果(数据准备)时可以执行其他操作,只有在拷贝数据的时候才会阻塞。此时该线程可以做一些其他的 CPU 计算,但是一般会伴随不停的访问请求结果这一操作

注意,阻塞与非阻塞的概念只有同步中才有,没有异步阻塞与异步非阻塞的说法,接下来说一下为什么

同步与异步

同步和异步关注的是消息通信机制

同步指发出调用请求后,请求跟随调用结果一起返回

异步指发出请求后,请求或者调用立即返回,在 IO 设备或者其他的机器操作完毕后,通过回调函数或者其他方式返回状态或者数据信息

比如我们使用消息队列来处理某个功能,一般来说发生消息后就不用管之后的操作了,该过程就是异步的。主线程不关心另一个线程怎么样,所以谈不上阻塞非阻塞

IO 和系统调用

所有的 IO 操作都会有系统调用的过程,同时所有的系统 IO 都分为两个阶段:等待就绪和操作。举例来说,读函数,分为等待系统可读和真正的读;同理,写函数分为等待网卡可以写和真正的写

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

需要说明的是等待就绪的阻塞是不使用 CPU 的,是在空等,这期间数据通过网线以电流的方式输入我们的电脑,并且被保存在缓冲区中;而真正的读写操作的阻塞是使用 CPU 的,即 CPU 将数据从缓冲区拷贝到目标位置的过程,这个时候 CPU 真正在干活

传统的 IO

这里使用普通的 read 和 write 命令来展示一下传统 IO 的弊端

  • 用户进程通过 read 方法向操作系统发起调用,此时上下文从用户态转向内核态
  • DMA 控制器把数据从硬盘(或者套接字的缓冲区)中拷贝到内核读缓冲区
  • CPU 把内核读缓冲区数据拷贝到应用缓冲区,然后上下文从内核态转为用户态,read 和数据一起返回

其过程如下图所示:
在这里插入图片描述

write 指令:

  • 用户进程通过 write 方法发起调用,上下文从用户态转为内核态
  • CPU 将应用缓冲区中数据拷贝到 socket 缓冲区
  • DMA 控制器把数据从 socket 缓冲区拷贝到网卡,上下文从内核态切换回用户态,write 返回

read 和 write 分别进行了两次内核态用户态切换和两次 CPU 复制操作,在操作系统中这些是可以被优化的

但是优化之前先处理一个问题,我们可以看到数据会先复制到中间的 socket buffer 中,我们很可能有一个问题就是为什么数据不能从磁盘直接复制到用户缓冲区?原因主要在下面两点:

1,权限隔离:操作系统的内核空间和用户空间是严格分离的,以防止恶意程序直接访问系统资源,造成系统不稳定或安全漏洞。内核负责管理硬件资源,包括磁盘读写,而用户空间的应用程序则运行在更高的抽象层次上
2,地址空间不同:内核空间和用户空间拥有各自的虚拟地址空间。用户缓冲区位于用户空间的虚拟地址范围内,而内核在执行I/O操作时使用的是内核缓冲区,这些缓冲区位于内核空间的地址范围内

DMA

DMA 是 Direct Memory Access,直接内存存取

DMA 是直接内存访问技术,他是一块主板上独立的芯片,它专门用来进行内存和 IO 设备的数据传输,他的主要作用是优化数据从磁盘拷贝到缓冲区这一过程
在这里插入图片描述
早期计算机中,用户进程需要读取磁盘数据,需要 CPU 中断和 CPU 参与(就是整个数据的传输过程,都要需要 CPU 亲自参与搬运数据的过程,数据会先从磁盘拷贝到 CPU 寄存器,然后再写入对应的缓冲区),因此效率比较低,发起 IO 请求,每次的 IO 中断,都带来 CPU 的上下文切换。 DMA 控制器接管了数据读写请求。并且加快了 IO 拷贝速度,从而减少 CPU 的处理时间

mmap 内存映射

零拷贝技术是优化拷贝次数的技术,以下的技术包括 mmap 都是零拷贝技术的一种

mmap 将用户空间的一段内存区域映射到内核空间,映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。即将用户空间和内核空间关联起来,例如堆外内存就是 mmap 零拷贝技术

内核缓冲区和应用缓冲区共享,从而减少了从内核缓冲区到用户缓冲区的一次 CPU 拷贝

sendfile

sendfile 方法 IO 数据对用户空间完全不可见,所以只能适用于完全不需要用户空间处理的情况,比如将磁盘中的数据复制到网卡

整个过程发生了两次用户态和内核态的上下文切换和三次拷贝,数据不经过用户区,只在内核态进行复制。简单介绍一下流程,就是数据存在于内核中时,并未被真正复制到 socket 关联的缓冲区内。取而代之的是,只有记录数据位置和长度的描述符被加入到 socket 缓冲区中。DMA 模块将数据直接从内核缓冲区传递给协议引擎,从而消除了遗留的最后一次复制

Linux2.4内核版本之后对 sendfile 做了进一步优化,通过引入新的硬件支持,这个方式叫做 DMA Scatter/Gather 分散/收集功能,将整个过程优化到两次用户态和内核态的上下文切换和两次拷贝

splice

Linux 从2.6.17支持 splice 数据从磁盘读取到 OS 内核缓冲区后,在内核缓冲区直接可将其转成内核空间其他数据 buffer,而不需要拷贝到用户空间,这是不是和 sendfile 有点像?

注意 splice 和 sendfile 的不同,sendfile 是 DMA 硬件设备不支持的情况下将磁盘数据加载到 kernel buffer(内核空间维护的缓存空间)后,需要一次 CPU copy,拷贝到 socket buffer

而 splice 是直接将两个内核空间的 buffer 进行 pipe 管道传输

#include <fcntl.h>
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);

常用的 IO 模型

在这里插入图片描述

BIO:同步阻塞 IO

同步阻塞 IO 模型,该模型用于描述一方发起调用后,阻塞等待另外一方返回的场景,举几个例子:

  • 应用程序发起 read 调用后,会一直阻塞,直到在内核把数据拷贝到用户空间
  • 用户请求服务器后,一直等待接口返回
  • 长连接

NIO:同步非阻塞 IO

同步非阻塞 IO 模型中,该模型用于描述一方发起调用后,虽然等待该请求的结果,但是我们依然执行自己的一些逻辑流程,然后通过什么回调通知或者定时轮训来获取最终结果

在普通的 NIO 中应用程序会一直轮询发起 read 调用(发起调用会降低 CPU 性能),在数据准备的时间中线程不挂起,直到磁盘准备好数据

数据就绪后,实际的 IO 操作会等待数据复制到应用进程的缓冲区中以后才返回

IO 多路复用

java 中的 NIO、Radis 中的单线程、nginx 中的主进程就是 IO 多路复用(使用选择器,缓冲区、通道来实现,通道将用户数据拷贝到缓冲区中,选择器让程序读取缓冲区中数据),IO 多路复用是 NIO 的一种,但是它的好处是可以在同一条阻塞线程上处理多个不同端口的监听
在这里插入图片描述

多路 IO 共用一个同步阻塞接口,任意 IO 可操作都可激活 IO 操作,这是对阻塞 IO 的改进。此时阻塞发生在 select/poll 的系统调用上,而不是阻塞在实际的 I/O 系统调用上。IO 多路复用的高级之处在于它能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select 等函数就可以返回

信号驱动 IO

这是同步 IO 的一种。信号驱动 I/O 与异步 I/O 的区别是从缓冲区获取数据这个步骤的处理,前者收到的通知是可以开始进行复制操作了,在复制完成之前线程处于阻塞状态,所以它仍属于同步 I/O 操作,而后者收到的通知是复制操作已经完成

AIO:异步 IO 模型

异步 IO 是基于事件或者回调机制实现的,也就是应用操作之后会直接返回(发送 read 直接得到结果),不会堵塞在那里。举个例子:

  • 用户下单时会立马得到下单结果,但是要等待一段时间后才可以收到下单成功通知

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python系列】pathlib模块

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

C语言项目——贪吃蛇,为什么用curses,定义上下左右

在Linux系统中&#xff0c;使用ncurses在程序编译时还要加上 -lcurses 即&#xff1a;gcc cursedemo.c -lcurses #include<curses.h> int main() {initscr(); //ncurse界面的初始化函数printw("This is a curses window.\n");//再ncurse模式下的printfgetc…

【代码随想录训练营第42期 Day22打卡 回溯Part1 - LeetCode 77. 组合 216.组合总和III 17.电话号码的字母组合

目录 一、做题心得 二、回溯基础知识 1.定义 2.适用问题 3.一个思想 4.代码实现 三、题目与题解 题目一&#xff1a;77. 组合 题目链接 题解&#xff1a;回溯 题目二&#xff1a;216.组合总和III 题目链接 题解&#xff1a;回溯 题目三&#xff1a;17.电话号码的字…

企元数智百年营销史的精粹:借鉴历史创造未来商机

随着时代的发展和科技的进步&#xff0c;传统营销方式正在经历前所未有的颠覆和改变。在这个数字化时代&#xff0c;企业需要不断创新&#xff0c;同时借鉴百年营销史的精粹&#xff0c;汲取历史经验&#xff0c;创造未来商机。而"企元数智"作为现代营销的代表&#…

骑行激情,燃动巴黎——维乐Angel Revo坐垫,赋能你的奥运梦想!

当奥林匹克圣火在塞纳河畔熊熊燃烧&#xff0c;巴黎的街头巷尾都弥漫着骑行的激情。2024年的夏天&#xff0c;自行车赛道上&#xff0c;每一圈轮毂的转动都凝聚着运动员的汗水与荣耀。金牌赛程已定&#xff0c;女子公路自行车决赛于7月27日20:30鸣枪&#xff0c;男子紧随其后&a…

【Nuxt】编写接口和全局状态共享

编写接口 ~/server/api/homeInfo.get.ts export default defineEventHandler((event) > {return {code: 200,data: {name: hello world}} })服务端有一些方法可以快速获取请求常见字段&#xff1a; getQuery(event)getMethod(event)await readBody(event)await readRawBo…

配置Cuttlefish 虚拟 Android 设备

google 参考资料&#xff1a; https://source.android.com/docs/setup/start?hlzh-cn https://source.android.com/docs/devices/cuttlefish/get-started?hlzh-cn Cuttlefish 开始 验证 KVM 可用性 Cuttlefish 是一种虚拟设备&#xff0c;依赖于宿主机上可用的虚拟化。 …

鸿蒙Harmony开发:通用焦点样式事件规范

基础概念 焦点、焦点链和走焦 焦点&#xff1a;指向当前应用界面上唯一的一个可交互元素&#xff0c;当用户使用键盘、电视遥控器、车机摇杆/旋钮等非指向性输入设备与应用程序进行间接交互时&#xff0c;基于焦点的导航和交互是重要的输入手段。焦点链&#xff1a;在应用的组…

Docker安装teslamate

要求 Docker&#xff08;如果不熟悉 Docker&#xff0c;请参阅安装 Docker 和 Docker Compose&#xff09;一台始终开启的机器&#xff0c;因此 TeslaMate 可以持续获取数据计算机上至少有 1 GB 的 RAM 才能成功安装。外部互联网访问&#xff0c;与 tesla.com 交谈 创建一个名…

【数据结构】队列篇

文章目录 1.队列1.1 队列的概念及结构 2. 队列的实现2.1 准备工作2.2 队列的初始化2.3 队尾入队列2.4 队头出队列2.5 获取队列头部元素2.6 获取队列队尾元素2.7 获取队列有效元素个数2.8 检测队列是否为空2.9 销毁队列 3. 代码整合 1.队列 1.1 队列的概念及结构 队列&#xff…

黑马Java零基础视频教程精华部分_15_基本查找/顺序查找、二分查找/折半查找、插值查找、斐波那契查找、分块查找、哈希查找

系列文章目录 文章目录 系列文章目录一、基本查找/顺序查找核心思想&#xff1a;从0索引开始挨个往后查找代码&#xff1a;练习&#xff1a;定义一个方法利用基本查找&#xff0c;查询某个元素在数组中的索引&#xff0c;数组包含重复数据。 二、二分查找/折半查找核心思想:属于…

LVS多模式集群攻略!

NAT模式下的lvs集群 lvs-nat概念&#xff1a;修改请求报文的目标IP,多目标IP的DNAT&#xff0c;本质是多目标IP的DNAT&#xff0c;通过将请求报文中的目标地址和目标端口修改为某挑出的RS的RIP和PORT实现转发 最终实现效果&#xff1a; 1.Director 服务器采用双网卡&#xff…

Qt入门(二):第一个Qt项目

新建项目 打开Qt Creator&#xff0c;新建项目&#xff0c;然后一路next 到这一步baseclass有三种选择&#xff1a; QMainWindow&#xff1a;主窗口基类&#xff0c;相较于QWidget&#xff0c;多了菜单栏等杂七杂八的东西。QWidget&#xff1a;最基础的窗口基类&#xff0…

编译运行 Byconity

我的系统是centos&#xff0c;因此用他们的docker编译并用他们的docker-compose运行&#xff0c;以下流程亲测可跑&#xff1a; 拉取并编译 https://github.com/ByConity/ByConity/tree/master/docker/debian/dev-env 运行 https://github.com/ByConity/ByConity/blob/master/d…

Matplotlib | 一文搞定Matplotlib从入门到实战演练!

文章目录 1 什么是Matplotlib1.1 Matplotlib的安装1.2 Matplotlib的基本使用 2 绘制直线3 绘制折线设置标签文字和线条粗细设置中文标题风格的设置 4 绘制曲线绘制曲线yx^2绘制正弦曲线和余弦曲线画布分区 5 绘制散点图绘制不同种类不同颜色的线 6 绘制条形图&#xff08;柱状&…

代码之外的生存指南——生产力

自己感觉今天都没有喝一口水的时间忙忙碌碌的工作了一天&#xff0c;但是到快下班或晚上回想一下今天自己到底在忙些什么的时候&#xff0c;却好像也没有做些什么对自己工作主线有意义的事情&#xff0c;大多时候时间都花费在了那些检查邮件、泡茶、拨打电话、开会议等干扰内容…

科普文:业务场景之常见10家HIS厂商概叙

智慧医院信息化经过几十年的发展&#xff0c;涌现出了一大批优秀的建设企业&#xff0c;我们选取了市面上部分主流的HIS厂商进行了汇集&#xff0c;包括厂商的发展情况、产品情况、技术情况、案例情况等。 卫宁健康 WINEX 口号&#xff1a;软件认知医疗 最新产品&#xff1a;…

集智书童 | 浙江大学 蚂蚁集团提出 PAI,一种无需训练减少 LVLM 幻觉的方法 !

本文来源公众号“集智书童”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;浙江大学 & 蚂蚁集团提出 PAI&#xff0c;一种无需训练减少 LVLM 幻觉的方法 &#xff01; 浙江大学 & 蚂蚁集团提出 PAI&#xff0c;一种无需训…

BERT预训练

一、动机 1、在NLP中的迁移学习中&#xff0c;使用预训练好的模型抽取词、句子的特征&#xff0c;不更新预训练好的模型&#xff0c;而是在需要构建新的网络来抓取新任务需要的信息&#xff0c;也就是最后面加上一个MLP做分类&#xff1b; 2、由于基于微调的NLP模型&#xff…

21. 合并两个有序链表(递归)

目录 一;题目&#xff1a; 二代码; 三&#xff1a;结果&#xff1a; 一;题目&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 二代码; /*** Definition for singly-linked list.* struct ListNode {* …