五种常见的IO模型

目录

一. IO的概述

1.1 什么是IO

1.2 IO的效率问题

1.3 同步IO和异步IO的概念

二. 阻塞式IO

三. 非阻塞式IO

四. 信号驱动式IO

五. IO多路复用

六. 异步IO

七. 总结


一. IO的概述

1.1 什么是IO

IO,表示输入输出,即:InPut / OutPut,访问外部设备读取数据或者向外部设备写数据。常见的文件读写操作、网络通信操作,其实都是IO的过程。、

在Linux操作系统下,我们认为一切皆是文件,只有操作系统有权利对文件进行读和写的操作,用户如果要读写文件,本质上都是使用操作系统的文件读写接口来实现的。

这里以阻塞式读取为例,分析IO操作所进行的工作:

  • 当read/recv时,如果缓冲区中没有数据,那就阻塞式等待数据就绪 -- 等待。
  • 当read/recv时,如果缓冲区中有数据,那么就将数据从缓冲区拷贝到应用层 -- 拷贝。

因此,我们可以认为,IO = 等待 + 拷贝。只要执行流(进程/线程)参与了等待和拷贝其中之一,那么就认为这个执行流进行了IO操作。

图1.1展示了在进行文件写文件操作(input)时系统所进行的工作,可分为三步:

  1. 将文件的内容和属性信息加载到内存中去。
  2. CPU在内存中对文件内容进行修改。
  3. 将内存中被修改后的文件内容写回到内存中。
图1.1 修改磁盘文件内容的步骤

1.2 IO的效率问题

由于IO要从外设读取数据或者向外设写数据,而在计算机体系中,硬件的效率由高到低的排序是:CPU寄存器 > 高速缓存 > 内存 > 磁盘 > 网卡,对于任意的IO操作,其实大部分时间都是在等待外设数据就绪,因此效率十分低下

结论:由于IO操作消耗大量时间在等待数据就绪,因此IO的效率很低。

在互联网行业中,提高IO效率是备受关注的,结合上面的分析,高效IO和低效IO的特点为:

  • 低效IO:单位时间内,等待时间长,拷贝数据时间短。
  • 高效IO:单位时间内,拷贝数据时间长,等待数据时间短。

因此,设法降低等待时间的占比,是提高IO效率的关键所在

1.3 同步IO和异步IO的概念

在了解同步IO和异步IO之前,首先了解同步和异步的概念:

  • 同步:就是指一个调用发出后不直接返回,直到调用完成拿到结果才返回。即:发起调用的执行流(进程/线程)自身来执行调用,在调用完成时由其自身拿到结果。
  • 异步:就是指一个调用发出后马上返回,暂时先不获取调用结果。即:调用者发起调用后,其自身不执行调用的方法,而是继续执行自己本身的方法,由被调用者执行调用的方法,当被调用者执行结束后,将结果反馈给调用者。

推而广之,我们这样这样理解同步IO和异步IO:

  • 同步IO:发起IO的执行流,其本身会参与到IO的工作,即拷贝数据或等待数据就绪,并且由这个执行流本身获取到IO的结果,这种IO操作称之为同步IO。
  • 异步IO:发起IO的执行流本身不参与IO工作,而是有另外一个执行流来进行IO操作,发起IO的线程只需要等待进行IO的执行流反馈回结果即可。

二. 阻塞式IO

阻塞式IO,就是当进行读数据或写数据时,如果外设条件没有就绪,就阻塞式的等待条件就绪。如:在read/recv时,如果缓冲区中没有数据,该进程/线程就自动被添加到特定的等待队列中去等待缓冲区中被写入数据,在等待的过程中,进程/线程 不执行其它的工作。

所有的IO操作,默认都是阻塞式的,非阻塞IO需要人为进行设置

图2.1 阻塞式IO的模型图

三. 非阻塞式IO

如果一个进程/线程在进行IO操作时,数据尚未就绪,那么读取接口不会阻塞,先返回执行其他的工作,数据就绪才进行读取。

非阻塞式IO,一般采用轮询检查的方法进行IO操作,即:通过循环,不断检查IO资源是否已经就绪,就绪就读取,不就绪就执行其他的工作。

图3.1 非阻塞式IO的模型图

IO操作默认是阻塞式的,有两种方法可以实现非阻塞式IO:

  • 在使用open打开文件/调用socket接口获得fd时,传入O_NONBLOCK/SOCK_NONBLOCK作为参数,实现非阻塞式IO。
  • 通过调用fcntl函数,对指定的fd设置非阻塞式IO。

这里重点介绍如图通过调用fcntl函数来设置非阻塞式的IO。

fcntl函数 -- 对特定fd设置非阻塞IO

函数原型:int fcntl(int fd, int cmd, .../*args*/)

函数参数:

  • fd:进行操作的文件描述符。
  • cmd:F_GETFL -- 获取文件状态、F_SETFL -- 设置文件状态
  • 缺省参数:当cmd为F_SETFL时,传入O_NONBLOCK可以设置非阻塞。

返回值:当cmd为F_SETFL时,返回当前的文件状态,当cmd为F_SETFL时,应当返回0,如果函数调用失败,则返回-1。

代码3.1通过提供SetNonBlock接口,对标准输入(fd = 0)进行非阻塞式读取,在SetNonBlock内部调用fcntl函数将指定的fd设置为非阻塞。但在使用read进行非阻塞读取时,有以下几点问题需要注意:

  • 如果调用read时底层资源尚未就绪而产生非阻塞,那么read会以读取出错的形式返回。
  • read如果出错,不仅会体现在返回值上,也会设置全局错误码errno。
  • 当因为数据未就绪而非阻塞时,错误码errno被设置为EWOULDBLOCK || EAGAIN,其余为真正的读取失败。
  • 在非阻塞式read读取时,还应当判断错误码是否为EINTR,表示是否因为进程收到信号而造成read终止,如果是,应当尝试再次读取。

其中 EWOULDBLOCK 和 EAGAIN 对应的错误码都是11,描述信息为:Resource temporarily unavailable,就是资源尚未就绪的意思。

代码3.1:非阻塞式IO

#include <iostream>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>

// 设置非阻塞IO函数
bool SetNonBlockIO(int fd)
{
    // 获取文件状态
    int fd_status = fcntl(fd, F_GETFL);
    if(fd_status < 0)
    {
        // 如果失败返回false,表示设置非阻塞失败
        return false;
    }

    // 在原有的文件状态下添加非阻塞状态
    fcntl(fd, F_SETFL, fd_status | O_NONBLOCK);
    return true;
}

int main()
{
    // 对标准输入设置非阻塞
    bool ret = SetNonBlockIO(0);
    if(!ret)
    {
        exit(1);
    }

    // 开始进行非阻塞IO操作
    char buffer[1024] = { 0 };
    while(1)
    {
        ssize_t sz = read(0, buffer, 1024);
        
        // 如果正常读取
        if(sz > 0)
        {
            buffer[sz - 1] = '\0';    // 设置字符串结束标识
            std::cout << "echo# " << buffer << ", [errno:" << errno << ", errorMsg:" << strerror(errno) << "]" << std::endl;
        }
        else   // 读取失败
        {
            // 如果是因为资源没有就绪而读取失败
            if(errno == EWOULDBLOCK || errno == EAGAIN)
            {
                std::cout << "errno:" << errno << ", errorMsg:" << strerror(errno) << std::endl;
            }
            else if(errno == EINTR)   // 因为进程收到信号而终止read
            {
                std::cout << "Interrupt because of signal, errno:" << errno << ", errorMsg:" << strerror(errno) << std::endl;
            }
            sleep(1);
        }
    }

    return 0;
}

四. 信号驱动式IO

通过自定义对29号SIGIO信号的处理函数来实现信号驱动式IO,当进程收到SIGIO信号的时候,就调用对应的处理函数来进行IO操作,这样保证在调用IO接口的时候数据一定是就绪的,在没有收到信号时不影响进程进行其他的工作,信号驱动式IO避免了阻塞等待资源就绪,提高了IO效率。

图4.1 信号驱动式IO的模型图

五. IO多路复用

一个进程能够同时等待多个文件描述符的资源是否就绪,只要其中一个文件描述符的资源就绪变为可读,那么进程就会去读取这个文件描述符对应的数据。由于可以同时等待多个文件描述符,只要其中一个资源就绪,就可以进行读取,这样就大大提高了IO的效率。

图5.1 IO多路复用的模型图

六. 异步IO

异步IO,就是发起IO的执行流本身不参与IO工作,而是有另外一个执行流来进行IO操作,发起IO的线程只需要等待进行IO的执行流反馈回结果。这样发起IO的执行流就不需要等到,可以处理其他的工作。

图6.1 异步IO的模型图

七. 总结

  • IO就是对外部设备进行输入输出操作的简称,IO的效率是十分低下的。
  • IO操作在单位时间内等待资源就绪的时长越短,IO效率就越高。
  • 共有5种常见的IO模型:阻塞式IO、非阻塞式IO、信号驱动IO、IO多路复用和异步IO,其中前四种属于同步IO。
  • 同步IO和异步IO的区别在于,是否由发起IO的执行流实际执行IO操作。

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

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

相关文章

Day22力扣打卡

打卡记录 替换子串得到平衡字符串&#xff08;滑动窗口&#xff09; 链接 由于是以后统计替换的子串&#xff0c;不可以直接使用hash表统计的每个次数大于 n / 4 的字符&#xff0c;再将其次数减去平衡数来得到答案&#xff0c;根据字符串的连贯性&#xff0c;使用 滑动窗口 …

Linux服务器配置信息查询命令

Linux服务器配置信息查询命令 一、查看CPU信息 查询系统的CPU的详细信息&#xff0c;包括每个处理器的型号、频率、缓存等级以及每个核心的数量。cat /proc/cpuinfo二、查看内存信息 查询系统的内存信息&#xff0c;包括可用内存、已用内存和缓存等。cat /proc/meminfo三、查…

飞控硬件介绍及其主要传感器特性解析

飞行控制器是无人机的关键组件之一&#xff0c;它主要由主控单片机、IMU传感器、电源和输出IO等部分构成。这些硬件和传感器的特性对于无人机的二次开发至关重要&#xff0c;其性能和质量直接关系到无人机的稳定性、飞行性能和功能扩展能力。 本文将带领新手开发者深入了解飞行…

【文件IO】认识文件

文章目录 认识文件文件的结构和目录文件路径 认识文件 我们先来认识狭义上的文件(file)&#xff0c;针对硬盘这种持久化存储的I/O设备&#xff0c;当我们想要进行数据保存时&#xff0c;往往不是保存一个整体&#xff0c;而是独立成一个个单位进行保存&#xff0c;这个独立的单…

jbase代码生成器(成型篇)

上一篇说到通用码表可以解决百分之八十的基础维护功能&#xff0c;剩下的百分二十的需要级联维护的界面可以用代码生成器生成代码&#xff0c;基于生成的代码拷贝再组装界面&#xff0c;来解决这百分之二十的工作量里的百分之八十工作量。 首先实现代码生成器 Class Jbase.Ma…

创建一个事务级临时表或者会话级临时表继续测试,在什么情况下临时表里的数据会消失

目录 一、测试事务级临时表 1、创建事务级临时表 2、插入测试数据 3、查看表中的数据 4、提交事务 5、再次查看表中数据 二、测试会话级临时表 1、创建会话级临时表 2、插入测试数据 3、查看表中的数据 4、提交事务再次查看数据 5、关闭当前会话 6、再次进入数据库…

项目管理之如何出道(下)

前言 是谁用烛火照亮整个中国&#xff1f;是一伙伙行走在高压线上的电力工人&#xff1b; 是谁用水枪保护千家万户&#xff1f;是一组组穿梭于大街小巷的消防队伍&#xff1b; 是谁用身体捍卫国防边境&#xff1f;是一队队跋涉在高山深林的可爱战士。 那么作为IT业界的我们&…

GPIO实验:ARM汇编代码实现LED灯亮灭控制

GPIO实验&#xff1a;ARM汇编代码实现LED灯亮灭控制 一、 汇编工程模板Makefile分析 NAMEasm-led #指定编译的源文件名字 CROSS_COMPILE arm-linux-gnueabihf- #指定交叉编译工具链前缀CC $(CROSS_COMPILE)gcc #指定gcc名字LD $(CROSS_COMPILE)ld #指定链接器名字…

“第六十五天”

固态硬盘&#xff1a;SSD 原理&#xff1a;基于闪存技术Flash Memory &#xff0c;属于电可擦除ROM&#xff0c;即EEPROM&#xff1b; 由闪存翻译层和存储介质组成&#xff1b;闪存翻译层负责翻译逻辑块号&#xff0c;找到对应页&#xff0c;存储介质是由多个闪存芯片构成的&…

Pycharm常用快捷键和替换正则表达式

原生快捷键的使用&#xff1a; 1.CtrlF&#xff1a;查找 2.CtrlZ&#xff1a;返回上一步 3.Alt 鼠标左键选择&#xff1a;多行同时编辑&#xff08;上、下、左、右键能够移动光标&#xff09; 按住Ctrl,左键点击&#xff0c;定位光标 编辑过程 URL常用的替换正则表达式&am…

阿里云99元的主机到底怎么样?

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 在云栖大会上&#xff0c;阿里云推出了一款绝对超级超值的99元云服务器&#xff0c;并号称是11月销量王。什么?云栖大会11月2号结束的&#xff0c;你就号称11月销量王&#xff0c;这是未卜先知啊。…

【算法 | 数论 No.1】AcWing1246. 等差数列

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【AcWing算法提高学习专栏】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&a…

【异常----finally和自定义异常】

文章目录 finally练习问题 异常的处理流程【异常处理流程总结】自定义异常类 finally 有些特定的代码&#xff0c;不论程序是否发生异常&#xff0c;都需要执行&#xff0c;比如程序中打开的资源&#xff1a;在程序正常或者异常退出时&#xff0c;必须要对资源进进行回收。另外…

2023.11.10联测总结

T 1 T1 T1求的是有多少个区间的异或和是 k k k的因子&#xff0c; n , k ≤ 1 0 5 n,k \leq 10^5 n,k≤105。 这道题用前缀和维护一下&#xff0c;暴力枚举所有区间就有 80 80 80分。 有一瞬间想过枚举因数&#xff0c;但是脑抽以为要 O ( n ) \mathcal O(n) O(n)枚举&#x…

计算机技术专业CSIT883系统分析与项目管理介绍

文章目录 前言一、学科学习成果二、使用步骤最低出勤要求 前言 本课程介绍了信息系统开发中的技术和技术&#xff0c;以及与管理信息技术项目的任务相关的方法和过程。 它研究了系统分析师、客户和用户在系统开发生命周期中的互补角色。 它涵盖了引出系统需求的不同事实调查技…

Java进阶API第二章

Java进阶API第二章 一. 抛出企业问题&#xff0c;脱离main测试&#xff0c;模块化编程 1.学校里如何测试的 //学校教的测试方法 public static void main(String[] args) {//2.本地测试//3.调用函数//4.看输出&#xff0c;查看结果是否符合预期//5.预期结果和测试结果是通过人工…

CSS 文字溢出省略号显示

1. 单行文本溢出显示省略号 需要满足三个条件&#xff0c;添加对应的代码&#xff1a; &#xff08;1&#xff09;先强制一行内显示文本&#xff1b; &#xff08;2&#xff09;超出的部分隐藏&#xff1b; &#xff08;3&#xff09;文字用省略号来替代省略的部分&#xf…

创建两个简单表A,B 。AB表有相关联的列。并在关联列上创建索引

目录 一、创建两个简单表&#xff0c;并进行外键关联 1、创建表A 2、创建表B&#xff0c;并且关联表A 二、在关联列上创建索引 三、检查是否成功 一、创建两个简单表&#xff0c;并进行外键关联 1、创建表A CREATE TABLE A (id NUMBER PRIMARY KEY,name VARCHAR2(50),d…

3.5、Linux:命令行git的使用

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 在Linux Centos7.6下安装git yum -y install git 注册一个gitee账号 进去注册就好&#xff0c;记住自己的用户名和密码。 创建一个仓库 点击复制&#xff0c;接着就可以在Linux上使用了 git clone git clone 刚才复制的地…

物联网AI MicroPython学习之语法 ustruct 打包和解压原始数据类型

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; ustruct 介绍 ustruct提供打包和解压原始数据类型的功能。 默认情况下&#xff0c;C类型以机器的本机格式和字节顺序表示&#xff0c;并在必要时通过跳过填充字节来正确对齐&#xff08;根据C编译器使用的规…