首页 > 其他分享 >五种IO模型的介绍

五种IO模型的介绍

时间:2024-08-29 20:57:37浏览次数:13  
标签:异步 模型 阻塞 描述符 五种 IO 拷贝 等待

前言

本文将介绍五种常见的IO模型:阻塞、非阻塞、信号驱动IO、多路复用、异步IO

文章的重点在于非阻塞与多路复用。而多路复用IO又有三种常见的方式。后续将会详细介绍。

这里就先熟悉一下IO模型、以及认识一下非阻塞IO的编写。

建立一个认识

IO分为:等+拷贝。比如往磁盘中写数据,会先等待,等待底层就绪(打开文件或者文件可写),然后才将用户的数据拷贝到内核缓冲区再由内核刷新到磁盘上。

所以什么是IO?IO就是等待条件就绪,然后进行拷贝。

而在实际的IO操作中,最耗时间的其实是等待,拷贝其实不花什么时间。提供IO的效率问题,就是围绕着如何减少等待的时间。

基于等待的方式不同,衍生出五种IO模型,下面就来认识一下。


阻塞IO

阻塞IO最常见,比如建立连接的俩台主机,主机A调用read ,而B主机没有发送数据,就会导致主机A阻塞等待消息的到来。

阻塞IO:在内核将数据准备好之前,系统调用会进入等待状态。所有的套接字,默认都是阻塞

阻塞IO是平常用的最多的模型,并且编写是最简单的。

以一个 例子总结阻塞IO

int main(){
    
    char buffer [1024];
    while(true){
        int n=read(0,&buffer,sizeof(buffer)-1);
        if(n>0){
            buffer[n]=0;
            std::cout<<"echo#"<<buffer;
        }
        else if(n==0){
            std::cout<<"read over"<<std::endl;
        }
        else{
            std::cout<<"出错!"<<std::endl;
        }
    }

    return 0;
}

如果没有输入数据,就会阻塞等待


非阻塞IO

如果数据没有就绪,就以出错的方式返回

非阻塞IO:内核没有将数据准备好,就以出错的方式返回,EAGAIN错误码被设置。

缺点:非阻塞会一直去轮询文件描述符,检测数据是否就绪, 对CPU来说是一直资源浪费

详解非阻塞IO

如果要将文件描述符设置为非阻塞状态,只需要fcntl系统调用即可。

设为非阻塞方式的步骤

SYNOPSIS
       #include <fcntl.h>

       int fcntl(int fd, int op, ... /* arg */ );

1.fcntl获取文件标记状态

2.对fd设置为非阻塞NON_BLOCK

fcntl的五种功能

  • 复制一个现有的描述符(cmd=F_DUPFD).
  • 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
  • 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
  • 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
  • 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)
     

常用到的只有获取和设置

关于OP NONBLOCK表示为非阻塞

下面依旧以读取为例子,介绍一下非阻塞

//设置文件描述符为非阻塞
void SetNonBlock(int fd){
    //获取状态标志位
    int fl=fcntl(fd,F_GETFL);
    if(fl<0){
        std::cout<<"文件描述符获取失败!"<<std::endl;
        exit(1);
    }
    fcntl(fd,F_SETFL,O_NONBLOCK|fl);
}
int main(){
    //设置文件为非阻塞
    SetNonBlock(0);

    char buffer [1024];
    while(true){
        int n=read(0,&buffer,sizeof(buffer)-1);
        if(n>0){
            buffer[n]=0;
            std::cout<<"echo#"<<buffer;
        }
        else if(n==0){
            std::cout<<"read over"<<std::endl;
        }
        else{
            if(errno==EAGAIN){
                std::cout<<"EAGAIN中...."<<std::endl;
            }
            else if(errno==EINTR) //硬件中断
            {
                std::cout<<"EINTR中...."<<std::endl;
            }
            else{
                std::cout<<"读取出错!"<<std::endl;
            }
            sleep(1);
        }
    }
    return 0;
}

先将文件描述符设置为非阻塞,然后往外设中读数据,为了便于观察,每次轮询就休眠一秒

观察到每隔一秒就出错返回一次。

为了将NONBLOCK返回与实际出错分开

以errno错误码为标记

  • EAGAIN:再试一次
  • EINTR:信号中断

设置文件描述符为非阻塞的操作


信号驱动IO

内核将数据准备好,通过信号的方式来通知程序IO

信号驱动也是同步吗?

这里介绍一下同步和异步的概念:
如果一个IO模型,同时进行了等待+拷贝的任意一种就是同步

反之任何都不进行的就是异步

信号驱动虽然没有实际的等,但是拷贝是由自己(本线程/进程)执行的,也是同步。

同时阻塞IO和异步IO:不仅进行等待,还进行拷贝,属于同步型IO。


 IO多路转接

多路转接:允许一个进程同时监听多个IO事件,并且在任意一个IO事件就绪时进行处理。

多路转接看上去与阻塞IO差不多,只不过通过系统调用,同时等待多个文件描述符。

常见的多路转接方式:

  • select
  • poll
  • epoll

 也是后续介绍的重点


异步IO

内核完成数据拷贝,并告知应用程序拷贝完成,可以操作数据


IO的实质就是等待+拷贝,实际上最影响性能的就是等待过程,为了提高效率。总是围绕着如何减少等待的时间。

 同步通信 vs 异步通信

同步:发起一个调用,在这个调用没有处理完毕时候,就会进入等待状态,直到将结果拿到。

异步:异步则是在发起调用时,不需要等待获取结果,而是直接返回。什么时候获取结果?在被调用者处理完毕后,通过回调函数来告知结果。

后续将详细介绍多路转接的模型,并且编写服务器echo,以及基于epoll的reator模型.

标签:异步,模型,阻塞,描述符,五种,IO,拷贝,等待
From: https://blog.csdn.net/m0_73299809/article/details/141651949

相关文章

  • IDEA报错:Error running 'XXXApplication' Error running XXXXApplication. Command li
     IDEA启动SpringBoot项目报错Errorrunning'XXXApplication'ErrorrunningXXXXApplication.Commandlineistoolong.ShortenthecommandlineviaJARmanifestorviaaclasspathfileandrerun   点击在高版本IDEA下只需要点击就会自动选择  低版本......
  • io进程----线程
    目录一丶概念二丶进程和线程的区别三丶资源四丶函数接口1.创建线程 pthread_create2.退出线程pthread_exit3.获取线程IDp_threadself​编辑4.回收线程资源五丶线程同步5.1概念5.2信号量5.3信号量的分类5.4函数接口1.初始化信号量2.申请资源3.释放资源......
  • 苹果 iOS / iPadOS 18 beta8和iOS / iPadOS 18.1 beta3版本更新
    苹果今日向iPhone和iPad用户推送了 iOS/iPadOS18开发者预览版Beta8 更新(内部版本号:22A5350a)和iOS/iPadOS18.1开发者预览版Beta3 更新(内部版本号:22B5034e),本次更新距离上次发布Beta/RC间隔8天。此次更新的iOS18Beta8已无限接近正式版,更新文件并未提到......
  • WPF-Prism Region使用
    Region:区域,我的理解,就是窗体上的一部分地方,不是整个窗体。所以区域里都是用户控件UserControl,就是为了解决在窗体上显示一个自定义的公用的控件的。共两种用法:1、原始的方法(不借助prism的依赖注入),用IRegionManager接口,来完成区域的注册和设置。注......
  • 2025秋招大语言模型落地实践面试题
    本文系统地从计算力基础设施、软件架构、数据资源、应用场景和脑科学五大核心维度对大模型实践中的问题进行解答。目录计算力基础设施1.1什么是云边端协同架构?1.2信息技术应用创新计划相关政策对企业的影响?软件架构2.1拥有自己的大语言模型(LLM)是否必要?2.2......
  • Php:Call to a member function fetch_all() on bool in ... #0 {main} thrown in ...
    一、软件版本  软件版本:phpstudy_proV8.2.9;二、错误描述  在编写完连接数据库,执行相关的操作的代码之后,在浏览器运行时报如下错误:Fatalerror:UncaughtError:Calltoamemberfunctionfetch_all()onboolinD:\phpstudy_pro\WWW\test2.cc\contact.php:77St......
  • 【ROS教程】用CLion编译和调试ROS包的全流程及可能遇到的问题
    @目录1.工作空间目录2.加载环境变量3.打开CLion4.配置CLion5.编译和调试软件包1.工作空间目录我们的一个工作空间目录应该是这样的2.加载环境变量先进入工作空间再加载source./devel/setup.bash3.打开CLion一定要在第二步的同一个终端下clion.sh如果打不开,......
  • 关于垂直领域大模型的探索和尝试
    最近这一两周看到不少互联网公司都已经开始秋招提前批面试了。不同以往的是,当前职场环境已不再是那个双向奔赴时代了。求职者在变多,HC在变少,岗位要求还更高了。最近,我们又陆续整理了很多大厂的面试题,帮助一些球友解惑答疑,分享技术面试中的那些弯弯绕绕。总结链接如下:《......
  • python接口自动化——接口登录获取session、cookie
    【参考】方法一参考链接如下,直接获取返回的cookie失败,拿到的cookies是空。(因为登录的url返回用f12看着是空的,用Charles才能看到,进行了重定向,返回了重定向的url)https://baijiahao.baidu.com/s?id=1781328761925882355&wfr=spider&for=pc 方法二参考链接如下,去拿session,再使用s......
  • 使用Flask快速构建Web后端项目:Python、Flask、Mysql、Migrate、SQLAlchemy、Login、Se
    Flask是一个用Python编写的轻量级Web应用框架。它设计简单且易于扩展,如果与Jinja2模板引擎和WerkzeugWSGI工具集结合使用,Flask可以用来快速开发小型到中型的网站。Flask鼓励快速开发和简洁的代码,同时保持了扩展性和灵活性。本文旨在如何使用Flask及其相关组件快......