【Linux】47.高级IO(1)

news2025/4/23 8:21:26

文章目录

  • 1. 高级IO
    • 1.1 五种IO模型
    • 1.2 高级IO重要概念
      • 1.2.1 同步通信 vs 异步通信
      • 1.2.2 阻塞 vs 非阻塞
    • 1.3非阻塞IO
      • 1.3.1 fcntl
      • 1.3.2 实现函数SetNoBlock
      • 1.3.3 轮询方式读取标准输入
      • 1.3.4 I/O多路转接之select
        • 1.3.4.1 初识select:
        • 1.3.4.2 select函数原型
        • 1.3.4.3 理解select执行过程


1. 高级IO

1.1 五种IO模型

[钓鱼例子]

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

阻塞IO是最常见的IO模型.

b1ec28c33d73553f0f533dfb2f7f6578

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

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

0a1f3215a2333d995b59518f6f625052

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

f74701d18ed4883f485655b0de6f8748

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

c8a62d36ae2870d11aeba3fd70877224

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

ddb9a78c361fe790231ca2e57908b990

小结:

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


1.2 高级IO重要概念

在这里, 我们要强调几个概念

1.2.1 同步通信 vs 异步通信

同步和异步关注的是消息通信机制.

  • 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回. 但是一旦调用返回,就得到返回值了; 换句话说,就是由调用者主动等待这个调用的结果;
  • 异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果; 换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果; 而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用.

另外, 我们回忆在讲多进程多线程的时候, 也提到同步和互斥. 这里的同步通信和进程之间的同步是完全不想干的概念.

  • 进程/线程同步也是进程/线程之间直接的制约关系
  • 是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系. 尤其是在访问临界资源的时候.

同学们以后在看到 “同步” 这个词, 一定要先搞清楚大背景是什么. 这个同步, 是同步通信异步通信的同步, 还是同步与互斥的同步


1.2.2 阻塞 vs 非阻塞

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

  • 阻塞调用是指调用结果返回之前,当前线程会被挂起. 调用线程只有在得到结果之后才会返回.
  • 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程.

1.3非阻塞IO

1.3.1 fcntl

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

函数原型如下.

#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).

我们此处只是用第三种功能, 获取/设置文件状态标记, 就可以将一个文件描述符设置为非阻塞.


1.3.2 实现函数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参数.

1.3.3 轮询方式读取标准输入

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
 
// 将文件描述符设置为非阻塞模式
void SetNoBlock(int fd) {
    int fl = fcntl(fd, F_GETFL);         // 获取文件描述符当前的标志
    if (fl < 0) {                         // 如果获取失败
        perror("fcntl");                 // 打印错误信息
        return;                          // 退出函数
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK); // 设置文件描述符为非阻塞模式
}
 
int main() {
    SetNoBlock(0);                       // 将标准输入(文件描述符0)设置为非阻塞模式
    
    while (1) {                          // 无限循环
        char buf[1024] = {0};            // 定义并初始化缓冲区
        ssize_t read_size = read(0, buf, sizeof(buf) - 1);  // 尝试从标准输入读取数据
        
        if (read_size < 0) {             // 如果读取失败(在非阻塞模式下,没有数据可读会返回-1)
            perror("read");              // 打印错误信息
            sleep(1);                    // 休眠1秒
            continue;                    // 继续下一次循环
        }
        
        printf("input:%s\n", buf);       // 打印读取到的输入内容
    }
    return 0;                            // 程序结束(实际上这行代码不会执行,因为有无限循环)
}

这段程序演示了非阻塞I/O的工作方式:

  1. 首先将标准输入(文件描述符0)设置为非阻塞模式
  2. 在无限循环中,程序尝试从标准输入读取数据
  3. 由于是非阻塞模式,当没有输入数据时,read()不会阻塞等待,而是立即返回-1,同时设置errno为EAGAIN或EWOULDBLOCK
  4. 程序捕获这个错误,打印错误信息,然后休眠1秒后再次尝试读取
  5. 当有数据输入时,read()会成功读取数据并返回读取的字节数,然后程序打印输入的内容

这种模式允许程序在没有输入时继续执行其他任务(在本例中只是休眠),而不是被阻塞在输入操作上,适用于需要同时处理多个I/O事件的场景。


1.3.4 I/O多路转接之select

1.3.4.1 初识select:

系统提供select函数来实现多路复用输入/输出模型.

  • select系统调用是用来让我们的程序监视多个文件描述符的状态变化的;
  • 程序会停在select这里等待,直到被监视的文件描述符有一个或多个发生了状态改变;

1.3.4.2 select函数原型

select的函数原型如下: #include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
          fd_set *exceptfds, struct timeval *timeout);

参数解释:

  • 参数nfds是需要监视的最大的文件描述符值+1;
  • rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合;
  • 参数timeout为结构timeval,用来设置select()的等待时间

参数timeout取值:

  • NULL:则表示select()没有timeout,select将一直被阻塞,直到某个文件描述符上发生了事件;

  • 0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。

  • 特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。

关于fd_set结构

其实这个结构就是一个整数数组, 更严格的说, 是一个 “位图”. 使用位图中对应的位来表示要监视的文件描述符.

提供了一组操作fd_set的接口, 来比较方便的操作位图

void FD_CLR(int fd, fd_set *set); // 用来清除描述词组set中相关fd 的位
int FD_ISSET(int fd, fd_set *set); // 用来测试描述词组set中相关fd 的位是否为真
void FD_SET(int fd, fd_set *set); // 用来设置描述词组set中相关fd的位
void FD_ZERO(fd_set *set); // 用来清除描述词组set的全部位

关于timeval结构

timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

1241a998a52b51f0b1b28870b85fa847

函数返回值:

  • 执行成功则返回文件描述词状态已改变的个数
  • 如果返回0代表在描述词状态改变前已超过timeout时间,没有返回
  • 当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds, exceptfds和timeout的值变成不可预测。

错误值可能为:

  • EBADF 文件描述词为无效的或该文件已关闭
  • EINTR 此调用被信号所中断
  • EINVAL 参数n 为负值。
  • ENOMEM 核心内存不足

1.3.4.3 理解select执行过程

理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd.

(1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。

(2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1) *

(3)若再加入fd=2,fd=1,则set变为0001,0011

(4)执行select(6,&set,0,0,0)阻塞等待

(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。

注意:没有事件发生的fd=5被清空。

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

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

相关文章

notepad++技巧:查找和替换:扩展 or 正则表达式

notepad 有很多优点&#xff1a;多标签&#xff0c;代码高亮&#xff0c;我最喜欢的是查找和替换。 除了可以一次性查找所有打开文件&#xff0c;还可以使用 扩展 or 正则表达式。 例如&#xff1a; 去掉空行&#xff1a;正则表达式&#xff1a; ^\s*$\r\n ^ 表示行首。\s*…

【图像标注技巧】目标检测图像标注技巧

介绍一些图像标注技巧。之前引用过别人的文章 yolo目标检测 技巧 trick 提升模型性能&#xff0c;deep research检测调研报告也可以进行参考。 拉框类的标注&#xff0c;如果你不确定哪种方法好&#xff0c;你可以把所标注区域的都剪切出来&#xff0c;然后站在屏幕一米之外眯…

MuJoCo中的机器人状态获取

UR5e机器人xml文件模型 <mujoco model"ur5e"><compiler angle"radian" meshdir"assets" autolimits"true"/><option integrator"implicitfast"/><default><default class"ur5e">&…

测试第四课---------性能测试工具

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

【C++】新手入门指南(下)

文章目录 前言 一、引用 1.引用的概念和定义 2.引用的特性 3.引用的使用 4.const引用 5.指针和引用的关系 二、内联函数 三、nullptr 总结 前言 这篇续上篇的内容新手入门指南&#xff08;上&#xff09;&#xff0c;继续带大家学习新知识。如果你感兴趣欢迎订购本专栏。 一、…

前后端分离项目在未部署条件下如何跨设备通信

其实我此前也不知道这个问题怎么解决&#xff0c;也没有想过—因为做的项目大部分都是前后端分离的&#xff0c;前端直接用后端的部署好的环境就行了。最近也是有点心高气傲开始独立开发&#xff0c;一个人又写前端又写后端也是蛮累的&#xff0c;即使有强有力的cursor也很累很…

基于Python的多光谱遥感数据处理与分类技术实践—以农作物分类与NDVI评估为例

多光谱遥感数据包含可见光至红外波段的光谱信息&#xff0c;Python凭借其丰富的科学计算库&#xff08;如rasterio、scikit-learn、GDAL&#xff09;&#xff0c;已成为处理此类数据的核心工具。本文以Landsat-8数据为例&#xff0c;演示‌辐射校正→特征提取→监督分类→精度评…

vscode python 代码无法函数跳转的问题

TL; DR; python.languageServer 配置成了 None 导致 vscode python 代码无法函数跳转 详细信息 mac 环境下 vscode 正常 command 鼠标左键 可以跳转到定义或者使用位置&#xff0c;但是我的为何不知道失效了 我一开始以为是热键冲突&#xff0c;结果发现 mac 好像没办法定…

Unity 脚本使用(二)——UnityEngine.AI——NavMesh

描述 Singleton class 用于访问被烘培好的 NavMesh. 使用NavMesh类可以执行空间查询&#xff08;spatial queries&#xff09;&#xff0c;例如路径查找和可步行性测试。此类还允许您设置特定区域类型的寻路成本&#xff0c;并调整寻路和避免的全局行为。 静态属性&#xff0…

从项目真实场景中理解二分算法的细节(附图解和模板)

遇到一个真实场景里使用二分算法的问题&#xff0c;本以为可以放心交给小师弟去做&#xff0c;结果出现了各种问题&#xff0c;在此梳理下二分算法的核心思想和使用细节。 文章目录 1.场景描述2.场景分析3.二分算法的精髓3.1 核心模板3.2 二分过程图解3.3 各种区间写法3.3.1 闭…

Jetson Orin NX 16G 配置GO1强化学习运行环境

这一次收到了Jrtson Orin NX, 可以进行部署了。上一次在nano上的失败经验 Jetson nano配置Docker和torch运行环境_jetson docker-CSDN博客 本次的目的是配置cuda-torch-python38环境离机运行策略。 Jetson Orin NX SUPER 1. 烧录镜像 参考链接在ubuntu系统中安装sdk manag…

深度学习3.5 图像分类数据集

%matplotlib inline import torch import torchvision from torch.utils import data from torchvision import transforms from d2l import torch as d2l代码执行流程图 #mermaid-svg-WWhBmQvijswiICpI {font-family:"trebuchet ms",verdana,arial,sans-serif;font-…

js原型链prototype解释

function Person(){} var personnew Person() console.log(啊啊,Person instanceof Function);//true console.log(,Person.__proto__Function.prototype);//true console.log(,Person.prototype.__proto__ Object.prototype);//true console.log(,Function.prototype.__prot…

【知识】性能优化和内存优化的主要方向

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 前言 现在有很多论文&#xff0c;乍一看很高级&#xff0c;实际上一搜全是现有技术的堆砌&#xff0c;但是这种裁缝式的论文依然能发表在很好的会议和期…

VS Code + GitHub:高效开发工作流指南

目录 一、安装 & 基本配置 1.下载 VS Code 2.安装推荐插件(打开侧边栏 Extensions) 3.设置中文界面(可选) 二、使用 VS Code 操作 Git/GitHub 1.基本 Git 操作(不输命令行!) 2.连接 GitHub(第一次使用) 三、克隆远程仓库到 VS Code 方法一(推荐): 方…

软件测试之接口测试常见面试

一、什么是(软件)接口测试? 接口测试&#xff1a;是测试系统组件间接口的一种测试方法 接口测试的重点&#xff1a;检查数据的交换&#xff0c;数据传递的正确性&#xff0c;以及接口间的逻辑依赖关系 接口测试的意义&#xff1a;在较早期开展&#xff0c;在软件开发的同时…

11、Refs:直接操控元素——React 19 DOM操作秘籍

一、元素操控的魔法本质 "Refs是巫师与麻瓜世界的连接通道&#xff0c;让开发者能像操控魔杖般精准控制DOM元素&#xff01;"魔杖工坊的奥利凡德先生轻抚着魔杖&#xff0c;React/Vue的refs能量在杖尖跃动。 ——以神秘事务司的量子纠缠理论为基&#xff0c;揭示DOM…

uniapp-商城-33-shop 布局搜索页面以及u-search

shop页面上有一个搜索&#xff0c;可以进行商品搜索&#xff0c;这里我们先做一个页面布局&#xff0c;后面再来进行数据i联动。 1、shop页面的搜索 2、搜索的页面代码 <navigator class"searchView" url"/pagesub/pageshop/search/search"> …

【dataframe显示不全问题】打开一个行列超多的excel转成df之后行列显示不全

出现问题如下图&#xff1a; 解决方案&#xff5e; display.width解决列显示不全 pd.set_option(display.max_columns,1000) pd.set_option(display.width, 1000) pd.set_option(display.max_colwidth,1000) pd.set_option(display.max_rows,1000)

Windows下Golang与Nuxt项目宝塔部署指南

在Windows下将Golang后端和Nuxt前端项目打包&#xff0c;并使用宝塔面板部署的步骤如下 一、Golang后端打包 交叉编译为Linux可执行文件 在Windows PowerShell中执行&#xff1a; powershell复制下载 $env:GOOS "linux" $env:GOARCH "amd64" go build…