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?什么是高效的IO? 为了理解后面的一个问题,我们首先要再重新理解一下什么是IO 在之前的网络介绍中ÿ…...
2023版 STM32实战11 SPI总线读写W25Q
SPI全称 英文全称:Serial peripheral Interface 串行外设接口 SPI特点 -1- 串行(逐bit传输) -2- 同步(共用时钟线) -3- 全双工(收发可同时进行) -4- 通信只能由主机发起(一主,多从机) 开发使用习惯和理解 -1- CS片选一般配置为软件控制 -2- 片选低电平有效,从…...
Spring Security认证源码解析(示意图)
建议先看完Spring Security总体架构介绍和Spring Security认证架构介绍,然后从FilterChainProxy的doFilterInternal函数开始,配合文章进行debug以理解Spring Security认证源码的执行流程。 在之前的Spring Security认证架构介绍中,我们已经知…...
2023.10.22 关于 定时器(Timer) 详解
目录 引言 标准库定时器使用 自己实现定时器的代码 模拟实现的两大方面 核心思路 重点理解 自己实现的定时器代码最终代码版本 引言 定时器用于在 预定的时间间隔之后 执行特定的任务或操作 实例理解: 在服务器开发中,客户端向服务器发送请求&#…...
【STM32】GPIO控制LED(寄存器版)
在开始之前记得先准备好环境: STM32F103核心板下载教程.pdf 林何/STM32F103C8 - 码云 - 开源中国 (gitee.com) 一、STM32的GPIO模块数据手册详解 每个GPIO端口对应16个引脚,例GPIOA(PA0~PA15)内核cpu就可以通过APB2总线对寄存器…...
Spring Boot OAuth 2.0整合—高级配置
一、概述 HttpSecurity.oauth2Login() 为定制OAuth 2.0登录提供了大量的配置选项。主要的配置选项被分组到它们的协议端点对应处。 例如,oauth2Login().authorizationEndpoint() 允许配置授权端点,而 oauth2Login().tokenEndpoint() 允许配置令牌端点。…...
软考-虚拟专用网原理与应用
本文为作者学习文章,按作者习惯写成,如有错误或需要追加内容请留言(不喜勿喷) 本文为追加文章,后期慢慢追加 by 2023年10月 虚拟专用网概念 虚拟专用网(Virtual Private Network)是一种通过…...
clock_property 时钟的常用属性
get_property [get_clocks] property_option 1. period get_property [get_clocks] period 查询所有clock 的周期,如果存在loops会生成CTE_loops.rpt 2.clock_network_pins 查询clock所有的pins 3.generated_clocks_extended 查询clock分频产生的generate…...
平板有必要买触控笔吗?推荐的ipad手写笔
iPad之所以能吸引这么多人,主要是因为它的功能出色。用来画画、做笔记,也是一种不错的体验。但如果只是用来看电视和打游戏的话,那就真的有点大材小用了。如果你不需要昂贵的苹果电容笔,也不需要用来专业的绘图,那你可…...
Qt扫描-QMoive 理论总结
QMoive 理论总结 一、概述二、使用1. 使用2. 信号发出时机 三、控制的相关槽函数四、信号 一、概述 QMovie类是一个使用QImageReader播放 动画 的方便类。这个类用于显示没有声音的简单动画,一般即是 gif 动画。如果要显示视频和媒体内容,请使用Qt Mult…...
类似东郊到家预约家政保洁小程序搭建
随着生活水平的提高,人们对健康养生的需求越来越重视,按摩作为一种传统的养生方式,备受关注。为了方便用户快速、方便地预约按摩服务,本文将介绍一款按摩预约小程序的开发。 首先,我们通过市场调研和分析发现…...
[补题记录] Atcoder Beginner Contest 325(E、F)
URL:https://atcoder.jp/contests/abc325 目录 E Problem/题意 Thought/思路 Code/代码 F Problem/题意 Thought/思路 Code/代码 E Problem/题意 有一个二维矩阵,D[i][j] 表示从 i 到 j 的距离。从 i 到 j 有两种方式: 坐汽车&…...
1024啊啊啊啊啊啊
1024 程序员节快乐,没什么想发的,只是想要个1024胸章。...
淘宝商品详情API接口(H5端和APP端),淘宝详情页,商品属性接口,商品信息查询
一、接口参数说明:提取淘宝商品详情页各项数据,包含skuid、价格、收藏数、加购数、月销售量、主图、标题、详情页图片等页面上可以看奥的数据都可以拿到。 点击获取key和secret 二、使用场景 1、商品销售情况分析,根据销量调整活动方案&am…...
JVM的几个面试重点
JVM的内存区域划分 JVM类加载机制 前言 Java程序最开始是一个 .java 的文件,JVM把它编译成 .closs 文件(字节码文件),运行 Java 程序, JVM 就会读取 .class 文件,把文件内容读取到内存中,构造出…...
[yolo系列:YOLOV7改进-添加CoordConv,SAConv.]
文章目录 概要CoordConvSAConv 概要 CoordConv(Coordinate Convolution)和SAConv(Spatial Attention Convolution)是两种用于神经网络中的特殊卷积操作,用于处理图像数据或其他多维数据。以下是它们的简要介绍&#x…...
【万字实操】可视化运维平台openGauss Datakit,带你轻松玩转openGauss 5.0
openGauss Datakit:openGauss社区推出的可视化的运维工具. 特性优势 初级用户学习openGauss门槛高让你望而却步?openGauss Datakit一键化安装企业版集群、监控、日志分析、SQL诊断,让你快速上手,快速部署,从容面对企业环境&#…...
《动手学深度学习 Pytorch版》 10.1 注意力提示
10.1.1 生物学中的注意力提示 “美国心理学之父” 威廉詹姆斯提出的双组件(two-component)框架: 非自主性提示:基于环境中物体的突出性和易见性 自主性提示:受到了认知和意识的控制 10.1.2 查询、键和值 注意力机制…...
C# 写入文件比较
数据长度:128188个long BinaryWriter每次写一个long 耗时14.7828ms StreamWriter每次写一个long 耗时44.0934 ms FileStream每次写一个long 耗时20.5142 ms FileStream固定chunk写入,循环操作数组,耗时13.4126 ms byte[] chunk new byte[d…...
医院设备利用(Use of Hospital Facilities, ACM/ICPC World Finals 1991, UVa212)rust解法
医院里有n(n≤10)个手术室和m(m≤30)个恢复室。每个病人首先会被分配到一个手术室,手术后会被分配到一个恢复室。从任意手术室到任意恢复室的时间均为t1,准备一个手术室和恢复室的时间分别为t2和t3…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
