如何理解高效IO

news2024/11/25 23:17:20

目录

前言

1.如何理解高效的IO

2.五种IO模型

3.非阻塞IO

4.非阻塞代码编写

总结 


前言

        哈喽,很高兴和大家见面!今天我们要介绍的关于IO的话题,在计算机中IO是非常常规的操作,例如将数据显示到外设,或者将数据从主机A发送到主机B……为了提高性能,减少IO的时间成为了一个人们比较关心的话题,而今天我们要介绍的是如何做才能提高IO效率。

1.如何理解高效的IO

IO:本质上是将数据从一方拷贝到另一方例如:调用read/recv读数据, 本质是将缓冲区的数据拷贝一份!但是拷贝数据的前提是要有数据,所以IO的过程包含两部分,一部分是等数据准备好,另一部分才是拷贝数据。因为拷贝数据的效率是由硬件本身决定的,所以要做到高效的IO,是要减少等的时间!

2.五种IO模型

举例说明:钓鱼的例子
张三坐在河边一动不动的等着鱼上钩
李四将鱼竿放在河边,然后就去做别的事情,然后隔一段时间看看有没有鱼上钩
五在鱼竿上放一个铃铛,将鱼竿放在河边,然后就去做别的事情,等铃铛响了就说明有鱼上钩了,然后把鱼钓上来
赵六带了一群鱼竿,然后都放在河边,然后就轮询的查看是否有鱼上钩
田七:找了一个人小刘,帮他钓鱼,等鱼钓上来,小刘通知田七,然后让田七把鱼拿走

其中张三对应于阻塞式IO
李四对应非阻塞式IO
王五对应信号驱动式IO
赵六对应多路转接/多路复用IO
田七对应异步IO
其中张三,李四,王五在效率上并没有什么差别!从整齐上来看李四和王五在钓鱼期间可以做其它的事情
信号驱动式IO:虽然是等信号发送了之后才会去拷贝数据,但是本质上也是等了!

四种方式,每个人都等了钓鱼->属于同步IO
第五种方式,没有参与IO阶段中任何阶段->属于异步IO
对于阻塞式IO和非阻塞式IO的差别:
相同点:都会进行数据拷贝
不同点:等的方式不同

阻塞式IO模型:

在内核将数据准备好之前, 系统调用会一直等待. 所有的套接字, 默认都是阻塞方式

非阻塞式IO模型:

如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK错误码.
非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符, 这个过程称为轮询. 这对CPU来说是较大的浪费, 一般只有特定场景下才使用.

信号驱动式IO模型:

内核将数据准备好的时候, 使用SIGIO信号通知应用程序进行IO操作

IO多路转接模型:

虽然从流程图上看起来和阻塞IO类似. 实际上最核心在于IO多路转接能够同时等待多个文件
描述符的就绪状态. 

异步IO:

由内核在数据拷贝完成时, 通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据). 

小结
任何IO过程中, 都包含两个步骤. 第一是等待, 第二是拷贝. 而且在实际的应用场景中, 等待消耗的时间往往都远远高于拷贝的时间. 让IO更高效, 最核心的办法就是让等待的时间尽量少. 

3.非阻塞IO

一个文件描述符, 默认都是阻塞IO.

fcntl()函数原型如下.

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );

传入的cmd的值不同, 后面追加的参数也不相同.
fcntl函数有5种功能:
 

复制一个现有的描述符(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).
我们此处只是用第三种功能, 获取/设置文件状态标记, 就可以将一个文件描述符设置为非阻塞

实现函数SetNoBlock
基于fcntl, 我们实现一个SetNoBlock函数, 将文件描述符设置为非阻塞.

void SetNoBlock(int fd) {
int fl = fcntl(fd, F_GETFL);
if (fl < 0) {
    perror("fcntl");
    return;
}
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}

使用F_GETFL将当前的文件描述符的属性取出来(这是一个位图).
然后再使用F_SETFL将文件描述符设置回去. 设置回去的同时, 加上一个O_NONBLOCK参数.

4.非阻塞代码编写

说明:用户向缓冲区输入数据,然后将数据读出来打印到显示器,显示器本质上也是一个文件,对应的文件描述符为0,此时将0号文件描述符对应的文件设置为非阻塞,当有数据的时候读取数据,没有数据的时候可以处理其它的业务,而不是阻塞式等待。

main.cc

#include"util.hpp"
#include<functional>
#include<vector>
using func_t = std::function<void()>;

#define INIT(v) do {\
    v.push_back(PrintLog);\
    v.push_back(Download);\
}while(0)
#define callback(cal) do{\
    for(auto& e: cal) e();\
}while(0);
int main()
{
    std::vector<func_t> cbs;
    INIT(cbs);
    setNoBlock(0);
    while(true) {
        char buf[1024];
        printf(">>> ");
        fflush(stdout);
        int ret = read(0,buf,sizeof(buf)-1);
        if(ret == 0) {
            std::cout<< "read end" << std::endl;
            break;
        }
        else if(ret > 0){
            buf[ret-1] = 0;
            std::cout << "echo# " << buf << std::endl;
        }
        else {
            //不输入的时候,底层没有数据,不算错误,只不过是以错误的形式返回了
            //如何区分是真的错了还是没有数据
            //EAGAIN 和 EWOULDBLOCK 都表示没有数据
            if(errno == EAGAIN || errno == EWOULDBLOCK) {
                std::cout << "没有数据" << std::endl;
                callback(cbs);
            }
            else if(errno == EINTR) continue;
            else {
                //真的错了
                std::cout << ret << "errno: "<< strerror(errno) << std::endl;
                break;
            }
        }
        sleep(1);
    }
    return 0;
}

util.hpp:

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

void setNoBlock(int fd) {
    int f1 = fcntl(fd,F_GETFL);
    if(f1 < 0) std::cerr<< "fcntl fail: " << strerror(errno) << std::endl; 
    fcntl(fd,F_SETFL,f1 | O_NONBLOCK);
}
void PrintLog() {
    std::cout << "this is a LOG" << std::endl;
}
void Download() {
    std::cout << "this is a Download" << std::endl;
}

运行截图:

总结 

        相信看完这篇文章之后,你一定可以理解要想实现高效的IO,必须要减少等的时间,如何减少等的时间呢?关于这个话题,一般采用IO多路转接的方案,IO多路转接包含select模型,poll模型,epoll模型,关于这三种模型,在后续的文章中为大家一一介绍,感谢大家的阅读,今天我们介绍的内容就结束了。

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

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

相关文章

将本地前端工程中的npm依赖上传到Nexus

【问题背景】 用Nexus搭建了内网的依赖仓库&#xff0c;需要将前端工程中node_modules中的依赖上传到Nexus上&#xff0c;但是node_modules中的依赖已经是解压后的状态&#xff0c;如果直接机械地将其简单地打包上传到Nexus&#xff0c;那么无法通过npm install下载使用。故有…

安防监控系统/视频云存储/监控平台EasyCVR服务器解释器出现变更该如何修改?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

软件测试/测试开发丨利用人工智能ChatGPT批量生成测试数据

点此获取更多相关资料 简介 测试数据是指一组专注于为测试服务的数据&#xff0c;既可以作为功能的输入去验证输出&#xff0c;也可以去触发各类异常场景。 测试数据的设计尤为重要&#xff0c;等价类、边界值、正交法等测试用例设计方法都是为了更全面地设计对应的测试数据…

Immutable.js API 简介

Immutable-js 这个库的实现是深拷贝还是浅拷贝&#xff1f;immutable 来源immutable.js三大特性&#xff1a; 持久化数据结构结构共享惰性操作 Immutable.js 的几种数据类型 immutable 使用 使用 npm 安装 immutable&#xff1a; 常用API介绍 MapListList.isList() 和 Map.isMa…

【Linux】页表讲解(一级、二级) 和 vm_area_struct ## 对于我前面博客内容的补充

对于前5篇进程相关知识的补充 前言正式开始页表讲解缺页中断页表是如何映射的页表的真正面目 vm_area_structmm_structvm_area_stuct 前言 前面我的博客中讲了很多关于进程的知识&#xff0c;但是有一些内容需要做一点补充&#xff0c;补充完后我的下一篇博客就开始讲线程相关…

云原生Kubernetes:pod亲和性与反亲和性

目录 一、理论 1.调度策略 2.亲和性与反亲和性案例 二、实验 1.亲和性与反亲和性 三、问题 1.节点批次打标签错误 2.for循环批量创建pod报错 四、总结 一、理论 1.调度策略 &#xff08;1&#xff09;对比 2.Pod 拓扑分布约束 &#xff08;1&#xff09;概念 使用 …

游戏ip多开安全指南:保障多重账号操作安全性

游戏多开是许多游戏玩家们常用的操作方式&#xff0c;而使用游戏ip进行游戏多开则能够进一步拓展多重账号的应用。然而&#xff0c;对于游戏多开使用游戏ip的安全性&#xff0c;我们也需要保持一定的警惕和注意事项。本文将为您分享有关游戏ip多开的安全指南&#xff0c;助您保…

C++中operator关键字(重载操作符)

转载地址&#xff1a; https://www.cnblogs.com/ZY-Dream/p/10068993.html operator是C的关键字&#xff0c;它和运算符一起使用&#xff0c;表示一个运算符函数&#xff0c;理解时应将operator整体上视为一个函数名。 这是C 扩展运算符功能的方法&#xff0c;虽然样子古怪&a…

vs2022 创建一个同时支持.net480和.net6.0的WPF项目

新建WPF项目&#xff0c;不要选.NET Framework框架的。如下图所示&#xff0c;选择第一个。&#xff08;选择.NET Framework框架改成.net6.0会报错&#xff09; 用记事本打开项目的csproj文件&#xff0c;修改TargetFrameworks标签&#xff0c;如下所示&#xff1a; <Pro…

C++之容器std::stack类empty、size、top、push、emplace、pop、swap应用总结(二百二十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

Bootstrap 框架学习笔记(基础)

来自于 Twitter&#xff0c;基于 HTML、CSS、JavaScript。 有关网站&#xff1a;Bootstrap中文网Bootstrap是Twitter推出的一个用于前端开发的开源工具包。它由Twitter的设计师Mark Otto和Jacob Thornton合作开发&#xff0c;是一个CSS/HTML框架。目前&#xff0c;Bootstrap最…

JVM面试题-类加载顺序、双亲委派、类初始化顺序(详解)

类加载器 JVM只会运行二进制文件&#xff0c;类加载器的作用就是将字节码文件加载到JVM中&#xff0c;从而让Java程序能够启动起来。 类加载负责执行类加载&#xff0c;去磁盘进行识别&#xff0c;识别完后加载到内存 类加载器的种类&#xff1a; 从上往下 启动类加载器&…

Unity的配置文件在安卓路径下使用的方法

Unity的配置文件在安卓路径下使用的方法 前言 之前我做过的很多使用配置文件的Unity项目&#xff0c;后面的有些项目也有在安卓路径下读取json文件的需求。这几天有个需求是获取在安卓路径下配置文件里的数据&#xff0c;我在网上查了一些案例&#xff0c;简单实现了这个需求…

swift 约束布局

添加约束布局 背景图瀑全屏 如何三等分 外面view容器没有约束

Laravel Swagger 使用完整教程

Swagger 使用 一、Swagger 基础1、 什么是Swagger2、 安装过程1 、composer安装2、添加服务提供者&#xff0c;引导框架运行时加载&#xff0c;在 app 配置文件&#xff0c;providers 选项中添加(laravel 5以上忽略此步骤)3、配置完成后&#xff0c;通过输入命令 **php artisan…

QT记事本+登陆界面的简单实现

主体头文件 #ifndef JSB_H #define JSB_H#include <QMainWindow> #include <QMenuBar>//菜单栏 #include <QToolBar>//工具栏 #include <QStatusBar>//状态栏 #include <QTextEdit>//文本 #include <QLabel>//标签 #include <QDebug&g…

什么样的应用程序适合使用Flutter开发桌面?

桌面应用开发的现状 在过去&#xff0c;桌面应用程序的开发通常需要使用特定于操作系统的工具和语言&#xff0c;如C、C#、Java等。这导致了高昂的开发成本和维护困难。尽管有一些跨平台桌面开发工具&#xff0c;如Electron和Qt&#xff0c;但它们在性能、用户体验和开发效率方…

Linus Torvalds接受来自微软的Linux Hyper-V升级

微软最近推送了一些变更&#xff0c;旨在改进即将发布的 Linux 内核 6.6 版本对 Hyper-V 的支持。这些改进包括在 Hyper-V 上支持 AMD SEV-SNP guest 和 Intel TDX guest。除了这两项&#xff0c;还有其他一些升级&#xff0c;如改进了 VMBus 驱动程序中的 ACPI&#xff08;高级…

阿里云产品试用系列-负载均衡 SLB

阿里云负载均衡&#xff08;Server Load Balancer&#xff0c;简称SLB&#xff09;是云原生时代应用高可用的基本要素。通过将流量分发到不同的后端服务来扩展应用系统的服务吞吐能力&#xff0c;消除单点故障并提升应用系统的可用性。阿里云SLB包含面向4层的网络型负载均衡NLB…

Flink TaskManger 内存计算实战

Flink TaskManager内存计算图 计算实例 案例一、假设Task Process内存4GB。 taskmanager.memory.process.size4096m 先排减JVM内存。 JVM Metaspace 固定内存 256mJVM Overhead 固定比例 process * 0.1 4096 * 0.1 410m 得到 Total Flink Memory 4096-256-410 3430m 计…