Linux C 程序 【05】异步写文件

news2024/12/21 8:36:36

1.开发背景

        Linux 系统提供了各种外设的控制方式,其中包括文件的读写,存储文件的介质可以是 SSD 固态硬盘或者是 EMMC 等。

        其中常用的写文件方式是同步写操作,但是如果是写大文件会对 CPU 造成比较大的负荷,采用异步写的方式比较合适,并且需要直接越过内核,直接通过 IO 访问,直接访问磁盘,关键词 O_DIRECT。可以有效降低 CPU 的使用率。

#ifdef __USE_GNU
# define O_DIRECT	__O_DIRECT	/* Direct disk access.  */
# define O_NOATIME	__O_NOATIME	/* Do not set atime.  */
# define O_PATH		__O_PATH	/* Resolve pathname but do not open file.  */
# define O_TMPFILE	__O_TMPFILE	/* Atomically create nameless file.  */
#endif

        添加宏定义,否者 O_DIRECT 显示未定义

#define _GNU_SOURCE

2.开发需求

设计实验:

        1)使用同步写硬盘的方式连续 100MB 的数据 10 次并统计每次写入的时间和速度

        2)使用异步写硬盘的方式连续 100MB 的数据 10 次并统计每次写入的时间和速度

3.开发环境

        ubuntu20.04 + RK3568 + Linux4.19.232 + 金士顿 SSD

4.实现步骤

4.1 实现代码

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <linux/fs.h>
#include <sys/time.h>

#include "com_file.h"
#include "app_log.h"

#define BUFFER_SIZE (1024 * 1024 * 100) // 100MB
#define TEST_FILE_PATH "/run/media/sata/output.dat"

/* 同步写测试 */
static void test_write_sync(char *file_path, char *buffer)
{
    /* 创建文件和路径 */
    common_file_create(file_path);

    /* 打开文件 */
    int fd = open(file_path, O_WRONLY | O_CREAT, 0644);
    if (fd < 0) 
    {
        alog_error("open failed\r\n");
        return;
    }

    /* 写数据 */
    if (write(fd, buffer, BUFFER_SIZE) != BUFFER_SIZE) 
    {
        alog_error("write failed\r\n");
        close(fd);
        return;
    }

    /* 关闭文件 */
    close(fd);
}

/* 异步写测试 */
static void test_write_async(char *file_path, char *buffer)
{
    /* 创建文件和路径 */
    common_file_create(file_path);

    /* 打开文件 */
    int fd = open(file_path, O_WRONLY | O_CREAT | O_DIRECT, 0644);
    if (fd < 0) 
    {
        alog_error("open failed\r\n");
        return;
    }

    /* 写数据 */
    if (write(fd, buffer, BUFFER_SIZE) != BUFFER_SIZE) 
    {
        alog_error("write failed\r\n");
        close(fd);
        return;
    }

    /* 关闭文件 */
    close(fd);
}

/* 主程序 */
int main()
{
    alog_info("%s start\r\n", __func__);

    char file_path[] = TEST_FILE_PATH;
    char *pdata_sync = NULL;
    char *pdata_async = NULL;

    /* 初始化同步内存 */
    pdata_sync = (char *)malloc(BUFFER_SIZE);
    if (pdata_sync == NULL)
    {
        alog_error("malloc failed\r\n");
        return 1;
    }
    alog_info("sync memory init ok\r\n");

    /* 初始化异步内存 */
    if (posix_memalign((void **)&pdata_async, 512, BUFFER_SIZE) != 0)    // 512 4096
    {
        alog_error("posix_memalign failed\r\n");
        return 1;
    }
    alog_info("async memory init ok\r\n");

    /* 填充数据 */
    for (long long int i = 0; i < BUFFER_SIZE; i++)
    {
        pdata_sync[i] = i & 0xFF;
        pdata_async[i] = i & 0xFF;
    }
    alog_info("data init ok\r\n");

    /* 计时*/
    struct timeval start_time;
    struct timeval end_time;

    /* 同步写测试 */
    for (int i = 0; i < 10; i++)
    {
        gettimeofday(&start_time, NULL);
        test_write_sync(file_path, pdata_sync);
        gettimeofday(&end_time, NULL);
        int usec_sync = (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_usec - start_time.tv_usec);
        double speed_sync = (double)BUFFER_SIZE / ((double)usec_sync / 1000 / 1000);
        alog_info("sync[%d] write test time: %d ms, speed: %lf MB/s\r\n", i, usec_sync / 1000, speed_sync / (1024 * 1024));
    }

    /* 异步写测试 */
    for (int i = 0; i < 10; i++)
    {
        gettimeofday(&start_time, NULL);
        test_write_async(file_path, pdata_async);
        gettimeofday(&end_time, NULL);
        int usec_async = (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_usec - start_time.tv_usec);
        double speed_async = (double)BUFFER_SIZE / ((double)usec_async / 1000 / 1000);
        alog_info("async[%d] write test time: %d ms, speed: %lf MB/s\r\n", i, usec_async / 1000, speed_async / (1024 * 1024));
    }

    /* 释放内存 */
    free(pdata_sync);
    free(pdata_async);

    return 0;
}

4.2 测试结果

        异步写硬盘速度更快,并且 CPU 占用更低,只有不到 20%,同步写硬盘 CPU 占用超过 90%

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

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

相关文章

凯酷全科技抖音电商服务的卓越践行者

在数字经济蓬勃发展的今天&#xff0c;电子商务已成为企业增长的新引擎。随着短视频平台的崛起&#xff0c;抖音作为全球领先的短视频社交平台&#xff0c;不仅改变了人们的娱乐方式&#xff0c;也为品牌和商家提供了全新的营销渠道。厦门凯酷全科技有限公司&#xff08;以下简…

精准提升:从94.5%到99.4%——目标检测调优全纪录

&#x1f680; 目标检测模型调优过程记录 在进行目标检测模型的训练过程中&#xff0c;我们面对了许多挑战与迭代。从初始模型的训练结果到最终的调优优化&#xff0c;每一步的实验和调整都有其独特的思路和收获。本文记录了我在优化目标检测模型的过程中进行的几次尝试&#…

STM8单片机学习笔记·GPIO的片上外设寄存器

目录 前言 IC基本定义 三极管基础知识 单片机引脚电路作用 STM8GPIO工作模式 GPIO外设寄存器 寄存器含义用法 CR1&#xff1a;Control Register 1 CR2&#xff1a;Control Register 2 ODR&#xff1a;Output Data Register IDR&#xff1a;Input Data Register 赋值…

国标GB28181平台EasyGBS在安防视频监控中的信号传输(电源/视频/音频)特性及差异

在现代安防视频监控系统中&#xff0c;国标GB28181协议作为公共安全视频监控联网系统的国家标准&#xff0c;该协议不仅规范了视频监控系统的信息传输、交换和控制技术要求&#xff0c;还为不同厂商设备之间的互联互通提供了统一的框架。EasyGBS平台基于GB28181协议&#xff0c…

如何使用checkBox组件实现复选框

文章目录 概念介绍使用方法示例代码我们在上一章回中介绍了DatePickerDialog Widget相关的内容,本章回中将介绍Checkbox Widget.闲话休提,让我们一起Talk Flutter吧。 概念介绍 我们在这里说的Checkbox也是叫复选框,没有选中时是一个正方形边框,边框内容是空白的,选中时会…

基于“2+1 链动模式商城小程序”的微商服务营销策略探究

摘要&#xff1a;本文探讨在竞争激烈的市场经济与移动互联网时代背景下&#xff0c;微商面临的机遇与挑战。着重分析“21 链动模式商城小程序”如何助力微商改变思路&#xff0c;通过重视服务、提升服务质量&#xff0c;以服务营销放大利润&#xff0c;实现从传统微商模式向更具…

1-1 STM32-0.96寸OLED显示与控制

1.0 模块原理图 2.0 0.96OLED简介 资料下载&#xff1a;https://jiangxiekeji.com/download.html 程序介绍&#xff1a;https://jiangxiekeji.com/tutorial/oled.html SSD1306是一款OLED/PLED点阵显示屏的控制器&#xff0c;可以嵌入在屏幕中&#xff0c;用于执行接收数据、显…

在Visual Studio 2022中配置C++计算机视觉库Opencv

本文主要介绍下载OpenCV库以及在Visual Studio 2022中配置、编译C计算机视觉库OpenCv的方法 1.Opencv库安装 ​ 首先&#xff0c;我们需要安装OpenCV库&#xff0c;作为一个开源库&#xff0c;我们可以直接在其官网下载Releases - OpenCV&#xff0c;如果官网下载过慢&#x…

QT:QDEBUG输出重定向和命令行参数QCommandLineParser

qInstallMessageHandler函数简介 QtMessageHandler qInstallMessageHandler(QtMessageHandler handler) qInstallMessageHandler 是 Qt 框架中的一个函数&#xff0c;用于安装一个全局的消息处理函数&#xff0c;以替代默认的消息输出机制。这个函数允许开发者自定义 Qt 应用…

网站灰度发布?Tomcat的8005、8009、8080三个端口的作用什么是CDNLVS、Nginx和Haproxy的优缺点服务器无法开机时

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把…

OpenGL ES 03 加载3张图片并做混合处理

OpenGL ES 02 加载3张图片并做混合处理 什么是纹理单元纹理单元的作用使用纹理单元的步骤详细解释加载图片并绑定到到GPU纹理单元采样器的设置1.设置采样器变量的纹理单元编号&#xff0c;目的是为了告诉纹理采样器&#xff0c;从哪个纹理单元采集数据2.如果你没有显式地设置采…

临床外显子组测序分析中的那些坑(上)

大规模并行测序技术或下一代测序已成为基因诊断和研究的标准技术&#xff0c;尤其是外显子组和基因组测序现在已经在世界范围内广泛应用于患者的分子诊断。在过去几年中&#xff0c;许多实验室都在努力应对基于全新技术建立基因检测工作流程的挑战。测序技术中持续引入新的仪器…

【Tomcat】第六站(最后一站啦!):数据的返回

1. 引言 前端资源比如html页面&#xff0c;进行返回。截止到目前我们写的项目架构不支持前端页面&#xff08;静态资源 &#xff09;。 2. 数据的返回 2.1 准备 为了能够写前端页面&#xff0c;新建一个项目。选择Maven项目&#xff0c;下一步&#xff0c;下一步。 加载完…

ai论文生成器:分享8款AI一键生成论文的写作软件

在撰写毕业论文的过程中&#xff0c;高效利用各类软件工具可以极大地提升写作效率与质量。以下是八个免费的神器软件工具&#xff0c;它们各自在论文撰写、文献管理、语法校对、数据可视化等方面发挥着重要作用。希望这些推荐能帮助你顺利完成毕业论文的写作。 千笔AI论文&…

【Ubuntu 20.04】notepad++的安装与汉化

一&#xff0c;简介 本文介绍如何在Ubuntu虚拟机中安装notepad&#xff0c;供参考。 二&#xff0c;操作步骤 2.1 notepad的安装 sudo snap install notepad-plus-plus

Cherno C++学习笔记 P45 拷贝与拷贝构造函数

在这一篇文章当中&#xff0c;我们会学习一下C当中的复制以及复制构造函数&#xff0c;当然&#xff0c;还会用一个相对比较完整的代码类作为例子。这也是我们第一次写一个相对比较长的和完整的代码。 对于C来说&#xff0c;理解复制是非常重要的&#xff0c;因为整个C变成可以…

uniapp入门 01创建项目模版

0安装 hbuilder x 标准版 1.创建模版工程 2.创建官方 案例工程 index.uvuewen 文件解析 <!-- 模版 标签 --> <template><view></view></template><!-- 脚本 --> <script>export default {data() {return {}},onLoad() {},methods:…

kubeadm安装K8s高可用集群之集群初始化及master/node节点加入calico网络插件安装

系列文章目录 1.kubeadm安装K8s高可用集群之基础环境配置 2.kubeadm安装K8s集群之高可用组件keepalivednginx及kubeadm部署 3.kubeadm安装K8s高可用集群之集群初始化及master/node节点加入集群calico网络插件安装 kubeadm安装K8s高可用集群之集群初始化及master/node节点加入ca…

【NLP】序列到序列(seq2seq)建模工具fairseq使用详解

文章目录 一、fairseq简介二、安装方式2.1 pip安装2.2 源码安装 三、fairseq命令工具3.1 fairseq-preprocess3.2 fairseq-train3.3 fairseq-generate3.4 fairseq-interactivate3.5 fairseq-score3.6 fairseq-eval-lm 4. 常见报错报错1 参考资料 一、fairseq简介 fairseq 是 Fa…

28、论文阅读:基于像素分布重映射和多先验Retinex变分模型的水下图像增强

A Pixel Distribution Remapping and Multi-Prior Retinex Variational Model for Underwater Image Enhancement 摘要介绍相关工作基于模型的水下图像增强方法&#xff1a;无模型水下图像增强方法&#xff1a;基于深度学习的水下图像增强方法&#xff1a; 论文方法概述像素分布…