【宝藏系列】一文带你梳理 Linux 的五种 IO 模型

【宝藏系列】一文带你梳理 Linux 的五种 IO 模型


在这里插入图片描述


文章目录

    • 【宝藏系列】一文带你梳理 Linux 的五种 IO 模型
    • 👨‍🏫前言
    • 1️⃣用户态和核心态
      • 1️⃣1️⃣用户态和核心态的切换
    • 2️⃣进程切换
    • 3️⃣进程阻塞
    • 4️⃣文件描述符(fd, File Descriptor)
    • 5️⃣缓存I/O
      • 5️⃣1️⃣缓存IO的缺点:
    • 6️⃣Linux下的五种I/O模型
      • 6️⃣1️⃣阻塞IO模型
      • 6️⃣2️⃣非阻塞IO模型
      • 6️⃣3️⃣IO复用模型
      • 6️⃣4️⃣信号驱动IO模型
      • 6️⃣5️⃣异步IO模型
      • 6️⃣6️⃣五种 IO 模型比较
    • 7️⃣ IO 复用之select、poll、epoll简介
      • 7️⃣1️⃣select
      • 7️⃣2️⃣poll
      • 7️⃣3️⃣epoll
      • 7️⃣4️⃣select、poll、epoll区别总结:


👨‍🏫前言


Linux下主要的IO主要分为:阻塞IO(Blocking IO),非阻塞IO(Non-blocking IO),同步IO(Sync IO)和异步IO(Async IO)。同步:调用端会一直等待服务端响应,直到返回结果。异步:调用端发起调用之后不会立刻返回,不会等待服务端响应。服务端通过通知机制或者回调函数来通知客户端。阻塞:服务端返回结果之前,客户端线程会被挂起,此时线程不可被CPU调度,线程暂停运行。非阻塞:在服务端返回前,函数不会阻塞调用端线程,而会立刻返回。

同步异步的区别在于:服务端在拷贝数据时是否阻塞调用端线程;阻塞和非阻塞的区别在于:调用端线程在调用function后是否立刻返回。要理解这些I/O,需要先理解一些基本的概念。

🌸🌸🌸🌷🌷🌷💐💐💐🌷🌷🌷🌸🌸🌸

1️⃣用户态和核心态


Linux系统中分为核心态(Kernel model)和用户态(User model),CPU会在两个model之间切换。

  • 核心态代码拥有完全的底层资源控制权限,可以执行任何CPU指令,访问任何内存地址,其占有的处理机是不允许被抢占的。内核态的指令包括:启动I/O,内存清零,修改程序状态字,设置时钟,允许/终止中断和停机。内核态的程序崩溃会导致PC停机。
  • 用户态是用户程序能够使用的指令,不能直接访问底层硬件和内存地址。用户态运行的程序必须委托系统调用来访问硬件和内存。用户态的指令包括:控制转移,算数运算,取数指令,访管指令(使用户程序从用户态陷入内核态)。

1️⃣1️⃣用户态和核心态的切换

用户态切换到核心态有三种方式:a.系统调用 这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如前例中fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。b.异常 当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。c.外围设备的中断 当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。

🌸🌸🌸🌷🌷🌷💐💐💐🌷🌷🌷🌸🌸🌸

2️⃣进程切换


为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换。因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。从一个进程的运行转到另一个进程上运行,这个过程中经过下面这些变化:

  • 保存处理机上下文,包括程序计数器和其他寄存器。
  • 更新PCB信息。
  • 把进程的PCB移入相应的队列,如就绪、在某事件阻塞等队列。
  • 选择另一个进程执行,并更新其PCB。
  • 更新内存管理的数据结构。
  • 恢复处理机上下文。
🌸🌸🌸🌷🌷🌷💐💐💐🌷🌷🌷🌸🌸🌸

3️⃣进程阻塞


正在执行的进程由于一些事情发生,如请求资源失败、等待某种操作完成、新数据尚未达到或者没有新工作做等,由系统自动执行阻塞原语,使进程状态变为阻塞状态。因此,进程阻塞是进程自身的一种主动行为,只有处于运行中的进程才可以将自身转化为阻塞状态。当进程被阻塞,它是不占用CPU资源的。

🌸🌸🌸🌷🌷🌷💐💐💐🌷🌷🌷🌸🌸🌸

4️⃣文件描述符(fd, File Descriptor)


FD用于描述指向文件的引用的抽象化概念。文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。

🌸🌸🌸🌷🌷🌷💐💐💐🌷🌷🌷🌸🌸🌸

5️⃣缓存I/O


缓存IO又被称作标准IO,大多数文件系统的默认IO 操作都是缓存IO。在Linux的缓存IO 机制中,操作系统会将 IO 的数据缓存在文件系统的页缓存( page cache )中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。


5️⃣1️⃣缓存IO的缺点:

数据在传输过程中需要在应用程序地址空间和内核进行多次数据拷贝操作,这些数据拷贝操作所带来的 CPU 以及内存开销是非常大的。

🌸🌸🌸🌷🌷🌷💐💐💐🌷🌷🌷🌸🌸🌸

6️⃣Linux下的五种I/O模型


Linux下主要有以下五种I/O模型:

  • 阻塞I/O(blocking IO)
  • 非阻塞I/O (nonblocking I/O)
  • I/O 复用 (I/O multiplexing)
  • 信号驱动I/O (signal driven I/O (SIGIO))
  • 异步I/O (asynchronous I/O)

6️⃣1️⃣阻塞IO模型

进程会一直阻塞,直到数据拷贝完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好。数据准备好后,从内核拷贝到用户空间,IO函数返回成功指示。阻塞IO模型图如下所示:

在这里插入图片描述


6️⃣2️⃣非阻塞IO模型

通过进程反复调用IO函数,在数据拷贝过程中,进程是阻塞的。模型图如下所示:

在这里插入图片描述


6️⃣3️⃣IO复用模型

主要是select和epoll。一个线程可以对多个IO端口进行监听,当socket有读写事件时分发到具体的线程进行处理。模型如下所示:

在这里插入图片描述


6️⃣4️⃣信号驱动IO模型

信号驱动式I/O:首先我们允许Socket进行信号驱动IO,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。过程如下图所示:

在这里插入图片描述


6️⃣5️⃣异步IO模型

相对于同步IO,异步IO不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的。异步过程如下图所示:

在这里插入图片描述


6️⃣6️⃣五种 IO 模型比较

阻塞IO和非阻塞IO的区别:调用阻塞IO后进程会一直等待对应的进程完成,而非阻塞IO不会等待对应的进程完成,在kernel还在准备数据的情况下直接返回。
同步IO和异步IO的区别:首先看一下POSIX中对这两个IO的定义:

A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
An asynchronous I/O operation does not cause the requesting process to be blocked;

两者的区别就在于synchronous IO做”IO operation”的时候会将process阻塞。
按照这个定义,之前所述的blocking IO,non-blocking IO,IO multiplexing都属于synchronous IO。注意到non-blocking IO会一直轮询(polling),这个过程是没有阻塞的,但是recvfrom阶段blocking IO,non-blocking IO和IO multiplexing都是阻塞的。而asynchronous IO则不一样,当进程发起IO 操作之后,就直接返回再也不理睬了,直到kernel发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被block。

在这里插入图片描述

🌸🌸🌸🌷🌷🌷💐💐💐🌷🌷🌷🌸🌸🌸

7️⃣ IO 复用之select、poll、epoll简介


epoll是linux所特有,而select是POSIX所规定,一般操作系统均有实现。


7️⃣1️⃣select

select本质是通过设置或检查存放fd标志位的数据结构来进行下一步处理。缺点是:

  • 单个进程可监视的fd数量被限制,即能监听端口的大小有限。一般来说和系统内存有关,具体数目可以cat /proc/sys/fs/file-max察看。32位默认是1024个,64位默认为2048个
  • 对socket进行扫描时是线性扫描,即采用轮询方法,效率低。当套接字比较多的时候,每次select()都要遍历FD_SETSIZE个socket来完成调度,不管socket是否活跃都遍历一遍。会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,就避免了轮询,这正是epoll与kqueue做的
  • 需要维护一个用来存放大量fd的数据结构,会使得用户空间和内核空间在传递该结构时复制开销大

7️⃣2️⃣poll

poll本质和select相同,将用户传入的数据拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或主动超时,被唤醒后又要再次遍历fd。它没有最大连接数的限制,原因是它是基于链表来存储的,但缺点是:

  • 大量的fd的数组被整体复制到用户态和内核空间之间,不管有无意义。
  • poll还有一个特点“水平触发”,如果报告了fd后,没有被处理,那么下次poll时再次报告该ffd。

7️⃣3️⃣epoll

epoll支持水平触发和边缘触发,最大特点在于边缘触发,只告诉哪些fd刚刚变为就绪态,并且只通知一次。还有一特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一量该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。epoll的优点:

  • 没有最大并发连接的限制。
  • 效率提升,只有活跃可用的FD才会调用callback函数。
  • 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递。

7️⃣4️⃣select、poll、epoll区别总结:

在这里插入图片描述

文章来源网络,如有侵权,请联系作者删除,谢谢!
来源:https://juejin.cn/post/6844903782094995470

在这里插入图片描述

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

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

相关文章

【笔记】MySQL行转列函数

GROUP_CONCAT()函数 创建表person_info,并插入数据 CREATE TABLE person_info (id bigint(20) NOT NULL AUTO_INCREMENT,name varchar(100) DEFAULT NULL,family varchar(100) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT8 DEFAULT CHARSETutf8;…

以太坊硬分叉后的可重入漏洞攻击

以太坊硬分叉后的可重入漏洞攻击 以太坊君士坦丁堡升级将降低部分 SSTORE 指令的 gas 费用。然而,这次升级也有一个副作用,在 Solidity 语言编写的智能合约中调用 address.transfer()函数或 address.send()函数时存在可重入漏洞。在目前版本的以太坊网络…

RecyclerView面试问答

RecycleView 和 ListView对比: 使用方法上 ListView:继承重写 BaseAdapter,自定义 ViewHolder 与 converView优化。 RecyclerView: 继承重写 RecyclerView.Adapter 与 RecyclerView.ViewHolder。设置 LayoutManager 来展示不同的布局样式 ViewHolder的编写规范化,ListVie…

基于蛾群算法优化的BP神经网络(预测应用) - 附代码

基于蛾群算法优化的BP神经网络(预测应用) - 附代码 文章目录 基于蛾群算法优化的BP神经网络(预测应用) - 附代码1.数据介绍2.蛾群优化BP神经网络2.1 BP神经网络参数设置2.2 蛾群算法应用 4.测试结果:5.Matlab代码 摘要…

会声会影2023全新中文专业版下载安装教程

熟练使用会声会影视频编辑工具,对视频创作过程的帮助是极大的。大家可以放心大胆地去研究会声会影的视频编辑技巧,会声会影2023与以往版本会声会影版本最大的区别是:账户制管理。可以通过账户添加或移除设备,非常便捷。该软件一直…

量化QAT QLoRA GPTQ

模型量化的思路可以分为PTQ(Post-Training Quantization,训练后量化)和QAT(Quantization Aware Training,在量化过程中进行梯度反传更新权重,例如QLoRA),GPTQ是一种PTQ的思路。 QAT…

【安卓】自定义View实现画板涂鸦等功能

一、实现效果 二、代码 1、MainActivity.class package com.lsl.mydrawingboarddemo;import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat;import android.os.Bundle; import android.os.Handler; import android.view.View; impo…

Langchain-React范式调用API —— 自定义工具

因为Langchain的代码也不是很复杂,因此 直接看代码会更好的学习。 一些说明,我已经放到了注释当中。 请各位看官享用。 代码样例 from langchain.agents import initialize_agent from langchain.llms import OpenAI from langchain.tools import Bas…

封装redis 分布式锁 RedisCallback

RedisCallback 是redis 一个回调接口,在 Redis 连接后执行单个命令,返回执行命令后的结果。 如果在使用 RedisCallback 时,需要自动获取 Redis 连接资源,使用完毕后并释放连接资源。 RedisTemplate 类提供了一个 execute 方法&am…

【C++进阶(一)】STL大法以及string的使用

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C   🔝🔝 STL标准库 1. 前言2. STL库的版本以及缺陷3. ST…

FastJson中JSON,JSONObject和JSONArray简单使用

JSON中提供了常用的对象和json数据间的转换方法。 JSONObject可以看作Map&#xff0c;使用key-value构建json对象。 JSONArray可以看作List&#xff0c;使用List可以简单构造json数组对象。1.pom.xml中引入依赖<dependency><groupId>com.alibaba.fastjson2</gro…

软考高级系统架构设计师系列论文九十一:论分布式数据库的设计与实现

软考高级系统架构设计师系列论文九十一:论分布式数据库的设计与实现 一、分布式数据库相关知识点二、摘要三、正文四、总结一、分布式数据库相关知识点 软考高级系统架构设计师系列之:分布式存储技术

远程调试环境

一、远程调试 1.安装vscode 2.打开vscode&#xff0c;下载插件Remote-SSH,用于远程连接 3.安装php debug 4.远程连接&#xff0c;连接到远端服务器 注&#xff1a;连接远程成功后&#xff0c;在远程依然要进行安装xdebug&#xff0c;刚才只是在vscode中进行的安装。 5.配置la…

R语言最简单的计算运行时间的方法

引言 要知道哪种编程的时间短&#xff0c;R语言中应该如何编码呢&#xff1f; 方法很简单&#xff0c;使用运行前Sys.time() 和运行后Sys.time()相减既可以得到运行时间。 代码如下 代码 #### 运行前时间timestart<-Sys.time()####程序运行 x <- rnorm(100000)y <…

UG\NX二次开发 使用BlockUI设计对话框时,如何设置默认的开发语言?

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,C\C++,Qt-CSDN博客 简介: NX二次开发使用BlockUI设计对话框时,如何设置默认的代码语言? 效果: 方法: 依次打开“文件”->“实用工具”->“用户默认设置”->“用户界面”->“操作记录”->“…

【机器学习】python基础实现线性回归

手写梯度下降的实现ykxb的线性回归 算法步骤&#xff1a; &#xff08;1&#xff09;构造数据&#xff0c;y3*x5; &#xff08;2&#xff09;随机初始化和&#xff0c;任意数值&#xff0c;例如9,10; &#xff08;3&#xff09;计算&#xff0c;,并计算 &#xff08;4&…

[ubuntu]linux服务器每次重启anaconda环境变量失效

云服务器每次重启后conda不能用了&#xff0c;应该是系统自动把设置环境变量清除了。如果想继续使用&#xff0c;则可以运行一下 minconda3激活方法&#xff1a; source ~/miniconda3/bin/activate anaconda3激活方法&#xff1a; source ~/anaconda3/bin/activate 你也修改b…

034 - year 年份类型

该YEAR类型是1字节类型&#xff0c;用于表示年份值。可以将其声明为 YEAR具有4个字符的隐式显示宽度&#xff0c;或等效于YEAR(4)显式显示宽度。 注意&#xff1a; 从MySQL 8.0.19开始&#xff0c;不建议YEAR(4) 使用具有显式显示宽度的数据类型&#xff0c;并且您应该期望在…

CCD 图形传感器

概述 CCD&#xff08;Charge Coupled Device&#xff09;是一种半导体器件&#xff0c;能够把光学影像转化为电信号。它是一种广泛使用的图像传感器&#xff0c;特别是在数码相机和摄像机中。 CCD图像传感器由许多排列成矩阵的微小像素组成&#xff0c;每个像素能够将光子转变…

只考一门数据结构,计算机学硕复录比1:1的山东双非学校考情分析

青岛理工大学 考研难度&#xff08;☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分析&#xff09;、院校概况、23专业目录、23复试详情、各专业考情分析、各科目考情分析。 正文1420字&#xff0c;预计阅读&#xff1a;3分钟 2023考情概况 青岛理工…