当前位置: 首页 > news >正文

I/O模型之非阻塞IO

简介

五种IO模型  

        阻塞IO  

        非阻塞IO  

        信号驱动IO  

        IO多路转接   

        异步IO

代码书写

        非阻塞IO

 

再次理解IO

什么是IO?什么是高效的IO?

为了理解后面的一个问题,我们首先要再重新理解一下什么是IO

在之前的网络介绍中,我们其实已经知道了IO的本质其实就是拷贝

        通过前面的 网络 过程中,我们所做的一切都是在把数据在拷贝来拷贝去,但是等这个部分就是由操作系统来控制的,因为把数据发送出去的前提是把数据从外设的磁盘中先把数据拷贝到发送缓冲区之中,通常IO的大部分时间的占比都是 "等" 这个行为造成的,拷贝数据其实快不了多少,拷贝速度只能依靠设备自身的配置,所以为了实现高效IO,我们只能 "等" ,这方面入手

        所谓的高效,就是把 "等" 的时间占比降低,只要减少 "等" 就是在实现高效,拷贝数据只能从硬件方面入手,换设备之类的啊,硬盘用SSD的啊,这类不是我们需要考虑的,我们这里只考虑 "等"

五种IO模型

我们用钓鱼的例子理解

故事背景

分析

解释

        其中阻塞式IO、非阻塞式IO、信号驱动式IO、多路转接/多路复用、异步IP统称为IO的五种模型,现在的全部的IO脱离不开这五种模型

        需要注意的是,我们通常大部分使用的其实还是阻塞式IO,因为简单,但是高效就是指的多路转接/多路复用

差别

阻塞IO

阻塞IO是最常见的IO模型

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

非阻塞IO

        非阻塞IO: 如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK错误码

        非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符, 这个过程称为轮询. 这对CPU来说是较大的浪费, 一般只有特定场景下才使用.

信号驱动IO

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

IO多路转接

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


 

        select只负责等这个行为,并且可以等多个文件描述符,是操作系统专门准备的一个接口,recvfrom只负责拷贝这个行为,也是操作系统专门准备的接口,因为这两个接口是解耦的,所以当select准备好了话,那么recvfrom就一定有数据可以拷贝,一定可以拷贝成功

        并且进程\线程的消耗是比较大的,但是多路转接就不会创建多个进程\线程,于是它的成本也是比较低的

异步IO

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

        操作系统自己等待数据,进程只是发起者,操作系统把数据都放在一个缓冲区之中,当满的时候,就直接执行进程传进来的方法就行了,进程本身不参与IO等待任何一个行为

小结

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

非阻塞IO

在代码接口中,我们可以通过传递参数来使用哪一种IO读取方式

不过我们通常是有一个函数可以专门来解决这方面的问题的

函数:fcntl

使用前先获取文件操作符

非阻塞选项

书写非阻塞转化函数

注意头文件的引入

阻塞式IO

如下图,0号文件描述符就是stdin,这里直接就是代表了键盘的输入了

设置为非阻塞

直接把之前写的函数用上

这里因为0号是键盘,而这里的1号就是屏幕,因为非阻塞所以键盘的输入是不会影响屏幕的打印的,这里的提示符一直在不停的循环打印(这里是sleep一秒的结果),0号当没有数据来的时候就会立刻返回,这样就可以做其他的事情了

我们可以进一步封装,当没有数据来的时候,可以让它做其他的事情

在循环内不断调用这个函数

存放的函数,用来演示作用

返回值怎么区别错误

因为非阻塞,当它没有数据的时候会立即返回,当你打印出来这个值的时候,会发现是-1和错误信息返回用的同一个值,那么我们如何区别真的错误还是因为没有数据导致的返回呢?

我们再一次查看read接口的返回值就可以知道,当被返回时还会有一个动作,即,错误码被立即设置

这时候我们可以直接通过打印出错误码的形式看到是因为什么原因导致的返回,其次我们知道错误码本质上是一个个的宏,利用这些宏,我们就可以实现区分这些错误信息了

结果显示,这里给的错误信息是资源未就绪,这样我们就可以知道是什么原因了

其实在read返回值里面专门提供了这么一个宏来标识,这类的信息

可以看出来其实就是 11

为此我们这样修改代码,将空闲时候执行其他函数的行为放到,错误码被置为-1并且本身不是错误的时候执行

这种错误其实是系统调用被中断了,即当正在读取的时候,一个信号过来,直接把读取中断了,这种错误也不算是失败错误,所以再做一个判断

至此非阻塞就不再深入了

源码

makefile
testNonBlock:main.ccg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -f testNonBlock

main.cc
#include "util.hpp"
#include <cstdio>
#include <vector>
#include <functional>using func_t = std::function<void()>;// 这是一个宏函数,用来把函数加载到数组当中去的
#define INIT(v)                  \do                           \{                            \v.push_back(pringLog);   \v.push_back(download);   \v.push_back(executeSql); \} while (0)// 这是一个宏函数,用来运行函数数组里面存放的函数的
#define EXEC_OTHER(cbs)            \do                             \{                              \for (auto const &cb : cbs) \cb();                  \} while (0)int main()
{std::vector<func_t> cbs;INIT(cbs); // 调用宏函数,运行存放在函数数组中的函数的setNonBlock(0);char buffer[1024];while (true){printf(">>> "); // 提示符fflush(stdout);ssize_t s = read(0, buffer, sizeof(buffer) - 1);if (s > 0){buffer[s - 1] = 0;std::cout << "echo# " << std::endl;}else if (s == 0){std::cout << "read end" << std::endl;break;}else{// 1.当不输入的时候,底层没有数据,这算是错误吗? 不算错误,只不过以错误的形式返回了(-1)// 2.那么如何区别,真的错误,还是因为底层没有数据导致的错误返回?// std::cout << "EAGAIN: " << EAGAIN << " EWOULDBLOCK: " << EWOULDBLOCK << std::endl;if (errno == EAGAIN){std::cout << "我没错, 只是没有数据" << std::endl;EXEC_OTHER(cbs); // 宏调用,用来把函数加载到函数数组中去}else if(errno == EINTR){continue;   // 系统信号导致的返回,直接让它继续读取就行了}else{//这类表示真正的错误,在前面已经把其他非错误的错误码处理解决之后,将错误信息打印出来std::cout << "s : " << s << " errno: " << strerror(errno) << std::endl;break;}}sleep(1);}
}

util.hpp
#pragma once#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <cerrno>// 这是一个讲文件描述符转为非阻塞式的函数
void setNonBlock(int fd)
{int f1 = fcntl(fd, F_GETFL);if(f1 < 0){std::cerr << "fcntl : " << strerror(errno) << std::endl;return;}fcntl(fd, F_SETFL, f1 | O_NONBLOCK); // 设置为非阻塞
}// 工具函数
void pringLog()
{std::cout << "this is a log" << std::endl;
}void download()
{std::cout << "this is a download" << std::endl;
}void executeSql()
{std::cout << "this is a executeSql" << std::endl;
}

下期预告:I/O多路转接之select

相关文章:

I/O模型之非阻塞IO

简介 五种IO模型   阻塞IO   非阻塞IO   信号驱动IO   IO多路转接    异步IO 代码书写 非阻塞IO 再次理解IO 什么是IO&#xff1f;什么是高效的IO&#xff1f; 为了理解后面的一个问题&#xff0c;我们首先要再重新理解一下什么是IO 在之前的网络介绍中&#xff…...

2023版 STM32实战11 SPI总线读写W25Q

SPI全称 英文全称&#xff1a;Serial peripheral Interface 串行外设接口 SPI特点 -1- 串行(逐bit传输) -2- 同步(共用时钟线) -3- 全双工(收发可同时进行) -4- 通信只能由主机发起(一主,多从机) 开发使用习惯和理解 -1- CS片选一般配置为软件控制 -2- 片选低电平有效,从…...

Spring Security认证源码解析(示意图)

建议先看完Spring Security总体架构介绍和Spring Security认证架构介绍&#xff0c;然后从FilterChainProxy的doFilterInternal函数开始&#xff0c;配合文章进行debug以理解Spring Security认证源码的执行流程。 在之前的Spring Security认证架构介绍中&#xff0c;我们已经知…...

2023.10.22 关于 定时器(Timer) 详解

目录 引言 标准库定时器使用 自己实现定时器的代码 模拟实现的两大方面 核心思路 重点理解 自己实现的定时器代码最终代码版本 引言 定时器用于在 预定的时间间隔之后 执行特定的任务或操作 实例理解&#xff1a; 在服务器开发中&#xff0c;客户端向服务器发送请求&#…...

【STM32】GPIO控制LED(寄存器版)

在开始之前记得先准备好环境&#xff1a; STM32F103核心板下载教程.pdf 林何/STM32F103C8 - 码云 - 开源中国 (gitee.com) 一、STM32的GPIO模块数据手册详解 每个GPIO端口对应16个引脚&#xff0c;例GPIOA&#xff08;PA0~PA15&#xff09;内核cpu就可以通过APB2总线对寄存器…...

Spring Boot OAuth 2.0整合—高级配置

一、概述 HttpSecurity.oauth2Login() 为定制OAuth 2.0登录提供了大量的配置选项。主要的配置选项被分组到它们的协议端点对应处。 例如&#xff0c;oauth2Login().authorizationEndpoint() 允许配置授权端点&#xff0c;而 oauth2Login().tokenEndpoint() 允许配置令牌端点。…...

软考-虚拟专用网原理与应用

本文为作者学习文章&#xff0c;按作者习惯写成&#xff0c;如有错误或需要追加内容请留言&#xff08;不喜勿喷&#xff09; 本文为追加文章&#xff0c;后期慢慢追加 by 2023年10月 虚拟专用网概念 虚拟专用网&#xff08;Virtual Private Network&#xff09;是一种通过…...

clock_property 时钟的常用属性

get_property [get_clocks] property_option 1. period get_property [get_clocks] period 查询所有clock 的周期&#xff0c;如果存在loops会生成CTE_loops.rpt 2.clock_network_pins 查询clock所有的pins 3.generated_clocks_extended 查询clock分频产生的generate…...

平板有必要买触控笔吗?推荐的ipad手写笔

iPad之所以能吸引这么多人&#xff0c;主要是因为它的功能出色。用来画画、做笔记&#xff0c;也是一种不错的体验。但如果只是用来看电视和打游戏的话&#xff0c;那就真的有点大材小用了。如果你不需要昂贵的苹果电容笔&#xff0c;也不需要用来专业的绘图&#xff0c;那你可…...

Qt扫描-QMoive 理论总结

QMoive 理论总结 一、概述二、使用1. 使用2. 信号发出时机 三、控制的相关槽函数四、信号 一、概述 QMovie类是一个使用QImageReader播放 动画 的方便类。这个类用于显示没有声音的简单动画&#xff0c;一般即是 gif 动画。如果要显示视频和媒体内容&#xff0c;请使用Qt Mult…...

类似东郊到家预约家政保洁小程序搭建

随着生活水平的提高&#xff0c;人们对健康养生的需求越来越重视&#xff0c;按摩作为一种传统的养生方式&#xff0c;备受关注。为了方便用户快速、方便地预约按摩服务&#xff0c;本文将介绍一款按摩预约小程序的开发。 首先&#xff0c;我们通过市场调研和分析发现&#xf…...

[补题记录] Atcoder Beginner Contest 325(E、F)

URL&#xff1a;https://atcoder.jp/contests/abc325 目录 E Problem/题意 Thought/思路 Code/代码 F Problem/题意 Thought/思路 Code/代码 E Problem/题意 有一个二维矩阵&#xff0c;D[i][j] 表示从 i 到 j 的距离。从 i 到 j 有两种方式&#xff1a; 坐汽车&…...

1024啊啊啊啊啊啊

1024 程序员节快乐&#xff0c;没什么想发的&#xff0c;只是想要个1024胸章。...

淘宝商品详情API接口(H5端和APP端),淘宝详情页,商品属性接口,商品信息查询

一、接口参数说明&#xff1a;提取淘宝商品详情页各项数据&#xff0c;包含skuid、价格、收藏数、加购数、月销售量、主图、标题、详情页图片等页面上可以看奥的数据都可以拿到。 点击获取key和secret 二、使用场景 1、商品销售情况分析&#xff0c;根据销量调整活动方案&am…...

JVM的几个面试重点

JVM的内存区域划分 JVM类加载机制 前言 Java程序最开始是一个 .java 的文件&#xff0c;JVM把它编译成 .closs 文件&#xff08;字节码文件&#xff09;&#xff0c;运行 Java 程序&#xff0c; JVM 就会读取 .class 文件&#xff0c;把文件内容读取到内存中&#xff0c;构造出…...

[yolo系列:YOLOV7改进-添加CoordConv,SAConv.]

文章目录 概要CoordConvSAConv 概要 CoordConv&#xff08;Coordinate Convolution&#xff09;和SAConv&#xff08;Spatial Attention Convolution&#xff09;是两种用于神经网络中的特殊卷积操作&#xff0c;用于处理图像数据或其他多维数据。以下是它们的简要介绍&#x…...

【万字实操】可视化运维平台openGauss Datakit,带你轻松玩转openGauss 5.0

openGauss Datakit:openGauss社区推出的可视化的运维工具. 特性优势 初级用户学习openGauss门槛高让你望而却步&#xff1f;openGauss Datakit一键化安装企业版集群、监控、日志分析、SQL诊断&#xff0c;让你快速上手&#xff0c;快速部署&#xff0c;从容面对企业环境&#…...

《动手学深度学习 Pytorch版》 10.1 注意力提示

10.1.1 生物学中的注意力提示 “美国心理学之父” 威廉詹姆斯提出的双组件&#xff08;two-component&#xff09;框架&#xff1a; 非自主性提示&#xff1a;基于环境中物体的突出性和易见性 自主性提示&#xff1a;受到了认知和意识的控制 10.1.2 查询、键和值 注意力机制…...

C# 写入文件比较

数据长度&#xff1a;128188个long BinaryWriter每次写一个long 耗时14.7828ms StreamWriter每次写一个long 耗时44.0934 ms FileStream每次写一个long 耗时20.5142 ms FileStream固定chunk写入&#xff0c;循环操作数组&#xff0c;耗时13.4126 ms byte[] chunk new byte[d…...

医院设备利用(Use of Hospital Facilities, ACM/ICPC World Finals 1991, UVa212)rust解法

医院里有n&#xff08;n≤10&#xff09;个手术室和m&#xff08;m≤30&#xff09;个恢复室。每个病人首先会被分配到一个手术室&#xff0c;手术后会被分配到一个恢复室。从任意手术室到任意恢复室的时间均为t1&#xff0c;准备一个手术室和恢复室的时间分别为t2和t3&#xf…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...