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

【Linux基础IO】深入解析Linux基础IO缓冲区机制:提升文件操作效率的关键

📝个人主页🌹:Eternity._
⏩收录专栏⏪:Linux “ 登神长阶 ”
🤡往期回顾🤡:暂无
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀Linux基础IO

  • 📒1. 什么是缓冲区
  • 📙2. stdio缓冲区机制
    • 🌞全缓冲、行缓冲与无缓冲
    • ⭐缓冲区刷新策略
  • 📚3. 典型函数与缓冲区操作
  • 📜4. 用户缓冲区和内核缓冲区
  • 📝5. FILE
    • 🌸实现C标准库函数
  • 📖6. 总结


前言:在Linux操作系统的广阔世界里,IO(输入/输出)操作是系统与外部设备(如硬盘、网络等)进行数据交换的基石。然而,直接而频繁地进行IO操作往往会成为系统性能的瓶颈,因为物理设备的访问速度远不及内存的处理速度。为了缓解这一矛盾,Linux引入了一系列高效的IO缓冲机制,通过在用户空间和内核空间之间设置缓冲区,以减少对物理设备的直接访问,从而提高数据处理的效率和系统的整体性能

学习Linux基础IO缓冲区,不仅是深入理解Linux操作系统内部工作原理的必经之路,也是优化系统性能、提升应用响应速度的关键技术之一。通过掌握IO缓冲区的概念、原理、管理机制以及优化策略,我们可以更好地理解和控制Linux系统的IO行为,从而在面对大数据量处理、高并发访问等挑战时,能够游刃有余地应对

让我们一同探索Linux IO缓冲区的奥秘,开启一段充满挑战与收获的学习之旅吧!


📒1. 什么是缓冲区

缓冲区(Buffer)在计算机科学中是一个重要的概念,它指的是一块用于临时存储数据的内存区域。缓冲区的主要目的是减少数据在传输或处理过程中的延迟,提高数据处理的效率,以及保护原始数据不被直接修改或破坏

验证缓冲区的存在:

printf("hello Linux");
sleep(1);

如果我们让这段伪代码运行,它不会立刻打印,而是等到程序结束时才会输出内容


关于缓冲区我们可以借用下图来理解
在这里插入图片描述

如果我们想将东西送给在异地的朋友时,我们不太可能亲自交到他的手上,我们可以通过菜鸟驿站将东西给他,当我们将快递交给快递站的时候,我们就认为将物品送出去了,但是在远方的朋友不会立刻受到快递,并且快递站也不会只单独送你这一个快递,它会等快递到达一定数量才会开始派送,这样会提高快递站的效率,这就和我们的缓冲区差不太多,所以缓冲区不会立刻刷新,它会等缓冲区内容到达一定数量,才会刷新缓冲区

缓冲区的主要作用:提高使用者的效率

  • 因为有缓冲区的存在,我们可以累计一部分在统一发送
  • 通过批量处理数据,缓冲区可以减少CPU中断的次数,从而提高系统性能
    在文件I/O操作中,操作系统可以将多个小的读写请求合并成较大的请求,以减少磁盘访问次数

📙2. stdio缓冲区机制

stdio缓冲区机制是C语言标准输入输出库(stdio.h)提供的一种用于提高数据读写效率的机制。缓冲区是一段内存区域,用于临时存储输入输出数据,以减少对磁盘或终端的直接读写次数,从而提高程序性能。stdio库中的函数,如printf、scanf、fread、fwrite等,都使用了缓冲区机制


🌞全缓冲、行缓冲与无缓冲

全缓冲:

  • 在全缓冲模式下,当缓冲区被填满时,才会进行实际的I/O操作
  • 默认情况下,对磁盘文件的读写操作采用全缓冲模式
  • 缓冲区的大小通常是固定的,如4096字节(但可以通过setvbuf函数调整)

行缓冲:

  • 在行缓冲模式下,当遇到换行符(\n)时,会执行I/O操作
  • 当流涉及终端(如标准输出stdout和标准输入stdin)时,通常使用行缓冲模式
  • 这使得输出能够按行显示,而不是等到缓冲区满时才显示

无缓冲:

  • 在无缓冲模式下,不对字符进行缓冲存储,即每次I/O操作都直接进行
  • 标准错误流(stderr)通常是无缓冲的,以确保错误信息能够立即显示

⭐缓冲区刷新策略

缓冲区刷新是指将缓冲区中的数据写入到目标设备(如磁盘或终端)的过程。stdio库提供了多种缓冲区刷新策略,以确保数据的及时性和完整性

以上讲的内容都是缓冲区的一般刷新策略

特殊情况:

  • 强制刷新
  • 当进程退出时,通常会隐式地刷新所有未刷新的缓冲区

📚3. 典型函数与缓冲区操作

在C语言中,stdio库中的典型函数与缓冲区操作密切相关。缓冲区是内存中的一块区域,用于临时存储输入输出数据,以提高程序性能


我们来看一段代码:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>int main()
{printf("hello printf\n");fprintf(stdout, "hello fprintf\n");fputs("hello fputs\n", stdout);const char *msg = "system call: hello write\n";write(1, msg, strlen(msg));return 0;
}

在这里插入图片描述

毋庸置疑,程序正常输出,我们来修改一下代码,看看会出现什么现象


我们在代码中加入 fork()

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>int main()
{printf("hello printf\n");fprintf(stdout, "hello fprintf\n");fputs("hello fputs\n", stdout);const char *msg = "system call: hello write\n";write(1, msg, strlen(msg));fork();                                                                                                                                                                                return 0;
}

在这里插入图片描述

让我们分析一下为什么只有一行代码的差距,却有两种不同的结果


代码分析

  • 我们直接向显示器打印时,显示器的刷新方式是行刷新,我们在输出的字符串中都有’\n’,我们在fork之前,所有数据均被刷新,包括system call
  • 重定向到log.txt,本质是往磁盘中写入数据,这时我们的刷新方式是全缓冲
  • 全缓冲就意味着,我们必须将缓冲区写满才会刷新,但是我们做不到,此时,数据依然存在于缓冲区
  • 目前我们谈论的缓冲区,只与C语言相关
  • C/C++提供的缓冲区,保存的一定是用户数据,属于进程在运行自己的数据,但是我们把数据交给OS时,数据就不再属于我们,而是属于OS
  • 当进程退出时,一般会刷新缓冲区,而刷新缓冲区属于"清空","写入"操作,fork后,任意一个进程退出,都会刷新缓冲区,这时就会发生写时拷贝
  • write属于系统调用,没有使用C语言缓冲区,直接将数据写入操作系统

📜4. 用户缓冲区和内核缓冲区

用户缓冲区和内核缓冲区是计算机系统中两个重要的概念,它们各自承担着不同的角色和功能,共同协作以提高系统的I/O性能和效率


在这里插入图片描述


📝5. FILE

在C语言中,FILE 是一个用于文件操作的结构体类型,它定义在 <stdio.h> 头文件中。FILE 结构体包含了文件操作的所有必要信息,比如文件的状态标志、当前的读写位置、缓冲区的地址等

在这里插入图片描述

我们在打开,关闭,读写文件时,都有一个FILE *的指针,所以我们进行输入,输出时,都需要FILE,FILE是一个结构体,里面包含了fd,FILE也会提供独立一个缓冲区,我们来验证一下

直接查看文件:

vim /usr/include/libio.h +246

在这里插入图片描述


🌸实现C标准库函数

这里也是简单实现了部分C标准库函数,感兴趣的朋友可以去看看
部分C标准库函数的模拟实现


📖6. 总结

在探索Linux基础IO缓冲区的旅程即将结束之际,我们不禁为这一强大而精细的机制所折服。IO缓冲区作为操作系统与用户程序之间数据传输的桥梁,不仅极大地提升了数据处理的效率,还巧妙地平衡了系统资源的使用与响应速度

通过本文的探讨,我们深入理解了Linux中IO缓冲区的核心概念、工作原理以及不同类型的缓冲区(如标准IO库缓冲、内核缓冲区等)之间的区别与联系。我们认识到,合理利用和配置缓冲区,对于优化程序性能、减少系统开销具有重要意义

在Linux的世界里,每一次对未知的探索,都是一次自我超越的旅程。愿我们都能在这条路上,越走越远,越走越宽。

在这里插入图片描述
希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Android数据序列化总结
  • Redis Bigkey
  • 从零到爆款:利用自养号测评打造Temu、亚马逊热销产品
  • 蠕虫病毒(网络安全小知识)
  • 【权限控制】一个通用的用户权限控制架构设计方案,可以适用于大多数应用场景
  • [数组计数法]#116. 开会时间
  • 戏曲多多 1.0.6.0 专为电视端设计的戏曲与生活内容APP,同样适用于安卓手机,方便老年人使用
  • 学习C4模型的新网站
  • 传奇开服需要多少钱?传奇开服服务器是自己买还是租?
  • Unity DOTS系列之托管/非托管Component的区别与性能分析
  • 一起操作一遍git,还不会你找我
  • tensorflow算子调用示例(MINIST)
  • 【项目实战】如何在项目中基于 Spring Boot Starter 开发简单的 SDK
  • ARM基础知识点及简单汇编语法
  • 【数据结构-栈】力扣71. 简化路径
  • 【347天】每日项目总结系列085(2018.01.18)
  • 〔开发系列〕一次关于小程序开发的深度总结
  • Angular 2 DI - IoC DI - 1
  • Fastjson的基本使用方法大全
  • javascript从右向左截取指定位数字符的3种方法
  • Linux gpio口使用方法
  • Magento 1.x 中文订单打印乱码
  • Mithril.js 入门介绍
  • PHP 的 SAPI 是个什么东西
  • PHP那些事儿
  • select2 取值 遍历 设置默认值
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • text-decoration与color属性
  • Vue.js-Day01
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • 笨办法学C 练习34:动态数组
  • 驱动程序原理
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 学习HTTP相关知识笔记
  • 转载:[译] 内容加速黑科技趣谈
  • 白色的风信子
  • 7行Python代码的人脸识别
  • 好程序员大数据教程Hadoop全分布安装(非HA)
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​Linux·i2c驱动架构​
  • # 利刃出鞘_Tomcat 核心原理解析(七)
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #在 README.md 中生成项目目录结构
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (4) PIVOT 和 UPIVOT 的使用
  • (C语言)逆序输出字符串
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (阿里云在线播放)基于SpringBoot+Vue前后端分离的在线教育平台项目
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (一) springboot详细介绍
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)Linq学习笔记
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...