write和fwrite

news2024/11/19 1:20:42

如果只是普通地以O_RDWR的flag去open一个文件朝里write(不考虑创建、扩增),那默认内核会把文件的这个页面读进来缓存在内核里的,也即所谓的page cache。随后再发起新的write syscall写相同的页面时,只要写在page cache里就可以结束syscall直接返回了。
在这里插入图片描述
内核的这个page cache有很多好处,比如你的程序对io还没到需要自己做用户态的读写缓存,那内核的这个机制就帮你省去了很多工作,毕竟page cache是在内存里的,而且可以拿来做read hit,相比于每次read/write都要访问磁盘,带来的性能优势还是很不错的,算是惠及大部分普通程序。
fwrite是用户态的glibc库,相当于把write的系统调用封装了一下,关键一点在于,他在用户态又多加了一个buffer,只有当你的fwrite写入量够多或者你主动fflush才会真的发起一个write syscall。
在这里插入图片描述
所以fwrite的好处是对于小量的写,减少syscall的次数,毕竟如果你每写一个字节都要发起一个syscall,然后特权级切换到内核,这是比较耗性能的。

程序的最终目的是要把数据写到磁盘上, 但是系统从通用性和性能角度,尽量提供一个折中的方案来保证这些。让我们来看一个最常用的写文件典型example,也是路径最长的IO。

{
    char *buf = malloc(MAX_BUF_SIZE);
    strncpy(buf, src, , MAX_BUF_SIZE);
     fwrite(buf, MAX_BUF_SIZE, 1, fp);
     fclose(fp);
 }

这里malloc的buf对于图层中的application buffer,即应用程序的buffer;调用fwrite后,把数据从application buffer 拷贝到了 CLib buffer,即C库标准IObuffer。fwrite返回后,数据还在CLib buffer,如果这时候进程core掉。这些数据会丢失。没有写到磁盘介质上。当调用fclose的时候,fclose调用会把这些数据刷新到磁盘介质上。除了fclose方法外,还有一个主动刷新操作fflush 函数,不过fflush函数只是把数据从CLib buffer 拷贝到page cache 中,并没有刷新到磁盘上,从page cache刷新到磁盘上可以通过调用fsync函数完成。

有人说,我不想通过fwrite+fflush这样组合,我想直接写到page cache。这就是我们常见的文件IO调用read/write函数。这些函数基本上是一个函数对应着一个系统调用,如sys_read/sys_write。调用write函数,是直接通过系统调用把数据从应用层拷贝到内核层,从application buffer 拷贝到 page cache 中。

最后是O_DIRECT,如果你在open一个文件的时候加上这个flag,那么后续对这个文件的所有read/write syscall都会bypass掉内核的page cache。也就是read/write直接发起disk io,不会在内核中缓存。
在这里插入图片描述
到这你会发现,O_DIRECT相当于把前面提到的各种buffer全扔了,直进直出,不存在什么locality、复用。
buffer,或者缓存虽然有好处,但也有适用条件以及额外的开销:

  • 如果你的程序的文件读写几乎没有locality或者什么热点,加缓存不会带来cache hit方面的性能提升。
  • 反而如果你写入的数据量很大,那用fwrite时,会发生你程序的buffer到glibc buffer一次拷贝。glibc buffer发起write syscall到page cache一次拷贝;而如果是普通write或O_DIRECT的write),只会发生你程序的buffer到page cache(disk的buffer cache)一次拷贝。
    -注意:2.4之后的内核page cache和disk buffer cache合并,所以page cache的内容直接可以移交给disk buffer cache用于写回
    所以从性能的角度,fwrite并不适合大量写的场景。然而光从这个角度并不能看出O_DIRECT的有无带来什么作用。O_DIRECT适用于,数据读写性能、一致性、locality、写回时机等等对你的程序已经重要到全都要你自己管理,这时内核自带的page cache那种粗粒度、不太可控的设施已经不能满足你的需求了。

使用直接IO需要遵守的一些限制:

  • 用于传递数据的缓冲区,其内存边界必须对齐为块大小的整数倍。
  • 数据传输的开始点,即文件和设备的偏移量,必须是块大小的整数倍
  • 待传递数据的长度必须是块大小的整数倍。

不遵守上述任一限制均将导致EINVAL错误。

最典型的就是数据库应用:
对数据库而言,依赖于page cache会带来非常多问题,比如:

  • writeback,也即写回磁盘同步的时机不可控。page cache可能在任何时候写回,包括你的事务做到一半,进程遭到调度,内核擅自把部分page cache上的内容写回磁盘,造成预期外的数据不一致。
    那么此时最好的解决方案是,所有对文件内容的cache,自己在用户态管理,bypas掉内核的page cache,而这就要借助O_DIRECT。什么时候写回,写回哪些,自己说了算。

最后提一下O_SYNC的问题,因为往往会和O_DIRECT一起用。从数据库的例子里可以看出,O_DIRECT既然控制写回,就和事务、数据一致性脱不了关系。一致性很重要的一个问题就是事情的发生顺序:写回真的做完了吗?
单靠O_DIRECT并不能保证写回的“完成”,因为O_DIRECT只是bypass掉page cache,保证数据直接提交到disk buffer cache,然而此时write即便返回,也不能保证disk buffer cache上的数据真的进入存储介质中(比如block layer的调度)。也即数据仍然在内存中,我们怎么才能保证write返回时数据就已经进入存储介质呢?答案就是O_SYNC。
所以O_DIRECT和O_SYNC一起使用,可以确保每一次写返回时,数据以bypass page cache的方式写,且已经进入存储介质。

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

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

相关文章

【博学谷学习记录超强总结,用心分享|产品经理基础总结和感悟13】

这里写目录标题第一章、概述第二章,内容服务产品分析框架:用户-平台-创作者内容服务平台优化思考第一章、概述 在分析文字类内容产品之前,我们先来思考一下内容产品的本质是什么?笔者认为,所有满足用户需求的信息服务…

aws beanstalk 使用docker平台部署beanstalk应用程序

参考资料 使用 Docker 平台分支 之前的文章分享过如何使用eb cli工具创建application和eb环境,本文介绍beanstalk支持的docker容器部署 关于beanstalk环境创建相关的资源和部署逻辑,参考之前的文章《aws beanstalk 使用eb cli配置和启动环境》 $ eb …

指南帮手——协议栈

通过 DNS 获取到 IP 后,就可以把 HTTP 的传输工作交给操作系统中的协议栈。协议栈的内部分为几个部分,分别承担不同的工作。上下关系是有一定的规则的,上面的部分会向下面的部分委托工作,下面的部分收到委托的工作并执行。应用程序…

PyTorch源码编译(windows)

1.打开pytorch源码仓库: https://github.com/pytorch/pytorch#from-source2.PyTorch用途与安装方法:3.Python与编译器版本要求 (Python3.7或者更高,编译器要求支持C17)4.如果要支持CUDA编程,要安装NVIDIA CUDA 11或者更高版本, 安装NVIDIA cuDNN v7或者更高版本注:CUDA不支持Ma…

使用 Flask 快速部署 PyTorch 模型

对于数据科学项目来说,我们一直都很关注模型的训练和表现,但是在实际工作中如何启动和运行我们的模型是模型上线的最后一步也是最重要的工作。 今天我将通过一个简单的案例:部署一个PyTorch图像分类模型,介绍这个最重要的步骤。 …

用一串Python代码爬取网站数据

如觉得博主文章写的不错或对你有所帮助的话,还望大家多多支持呀!关注、点赞、收藏、评论。 目录一.编码问题二、文件编码三、基本方法四、登录五、断线重连六、正则匹配Excel操作转换网页特殊字符一.编码问题 因为涉及到中文,所以必然地涉及…

MV*系列架构模型

下文仅代表个人理解,可能会有偏差或错误,欢迎评论或私信讨论。 MVC 从软件架构模型角度 MVC 是比较“古老”的架构模型,后面的 MV* 都是基于它进行拓展。MVC 出现的意义是为了提高程序的可维护性与拓展性。在 View 层与 Model 层中添加了 C…

如何分享让人眼前一亮的代码

作为一名软件工程师,会经常需要在工作和写作中粘贴代码片段以作示例,如果不关注代码的格式随手一粘,别人看到的画风就可能是这样:那么,该如何才能快速且优雅地分享代码片段呢?Raycast ray.so 或许是一个值…

2020-12-31 学习74HC595真值表与时序图

考资料教你74hc595时序图怎么看知识详解 - 电子常识 - 电子发烧友网 74HC595是串行输入并行/串行输出的移位锁存器。SHCP是移位脉冲,前沿(上升沿)有效,STCP是锁存脉冲,前沿有效,DS是输入信号,M…

动态规划算法刷题笔记【线性dp】

递推 斐波那契(Fibonacii)数列的递推公式:F(n) F(n -1) F(n - 2) 错排问题:F(n) (n-1) * [F(n-1)F(n-2)] 解释 例题 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法 思路 要想跳到第…

代码随想录算法训练营第4天 24.两两交换链表中的节点、19. 删除链表的倒数第N个节点、160.链表相交

代码随想录算法训练营第4天 24.两两交换链表中的节点、19. 删除链表的倒数第N个节点、160.链表相交 两两交换链表中的节点 力扣题目链接(opens new window) 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部…

C++中的多态

目录 多态的定义及实现 多态的构成条件 虚函数 虚函数重写 虚函数重写的两个例外: override 和 final(C11) 重载、覆盖(重写)、隐藏(重定义)的对比 抽象类 多态的原理 虚函数表 多态的概念:字面的意思就是多种形态,完成某个行为&…

利用MDK的FLM文件生成通用flash驱动

文章目录前言一、FLM文件是什么?二、FLM文件结构1.FlashPrg.c2.FlashPrg.c三、解析FLM文件1.解析flm文件四、设计flash驱动抽象层五、快速使用前言 在进行Flash操作时,一般我们需要设计一套Flash抽象层,至少要包括flash的init,re…

C++STL之stack容器和优先级队列底层详解

一:stack容器1.1:容器适配器概念:容器适配器是用特定类封装作为其底层的容器,并提供一组特定的成员函数来访问元素,stack的底层容器可以是任意的类模板,或者一些其他的容器类,这些容器类应该支持…

JavaScript详解

目录 1.JavaScript基础知识 1.1 JavaScript概述 1.1.1 JavaScript历史 1.1.2 JavaScript是什么 1.1.3 JavaScript的作用 1.1.4 HTML/CSS/JS的关系 1.1.5 基本特点 1.1.6 浏览器执行JS简介 1.1.7 JavaScript脚本语言的组成 1.2 JavaScript使用方法 1.3 JavaScript输…

论文创新及观点2

题目 Zero-Shot Visual Recognition using Semantics-Preserving Adversarial Embedding Networks 摘要 基于visual-semantic embedding,的ZSL方法存在信息损失(semantic loss),的问题,在训练过程中,如果某些语义信息对分类的区分性不大&a…

「项目管理」如何做好研发FO角色?

角色定位 FO (Feature Owner),项目某一阶段/版本迭代生命周期的总负责人。基于从需求发起、研发接入、上线等项目过程阶段,可以根据职责本位不同来推荐具体项目成员、干系人担任FO角色,前端、 客户端 、服务端、测试、…

Spring事务和事务传播机制

⭐️前言⭐️ 事务是作为一名后端程序员,必须去要了解清楚的东西,因为它决定了程序的正常运行以及与程序运行效率之间的权衡,这篇文章我们就来了解一下Spring事务和事务传播机制。 🍉欢迎点赞 👍 收藏 ⭐留言评论 &am…

【阶段三】Python机器学习08篇:机器学习项目实战:决策树分类模型

本篇的思维导图: 决策树模型简介 决策树模型的基本原理是通过对一系列问题进行if/else的推导,最终实现相关决策。 下图所示为一个典型的决策树模型——员工离职预测模型的简单演示。该决策树首先判断员工满意度是否小于5,若答案为“是”,则认为该员工会离…

07、ThingsBoard本地打镜像上传到harbor

1、Harbor是什么? Harbor是为企业用户设计的容器镜像仓库开源项目,包括了权限管理(RBAC)、LDAP、审计、安全漏洞扫描、镜像验真、管理界面、自我注册、HA等企业必需的功能,同时针对中国用户的特点,设计镜像复制和中文支持等功能。 2、安装Harbor 2.1、下载地址 Tags g…