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

1.开发背景

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

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

cpp 复制代码
#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 显示未定义

cpp 复制代码
#define _GNU_SOURCE

2.开发需求

设计实验:

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

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

3.开发环境

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

4.实现步骤

4.1 实现代码

cpp 复制代码
#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%

相关推荐
别动我齐刘海1 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
玖石书3 小时前
Ubuntu 24.04 UFW 全命令攻略:从入门到端口开放实战
linux·运维·ubuntu
xiaoqiMikko3 小时前
Linux 实战(七):useradd、sudoers、umask、SGID、软链 —— 三台真机实测
linux·centos
拂拉氏5 小时前
【知识讲解】 Linux之动静态库的了解
linux·运维·服务器·动静态库
Fcy6486 小时前
Linux下 五种IO模型的认识与⾮阻塞IO的实现
linux·服务器·io
Mikko76 小时前
Linux 重启后日志没了?进程被 OOM 杀了去哪看?logrotate 之后日志还往旧文件写?三台真机实测日志与性能排查
linux·运维·centos
书生执笔画浮沉6 小时前
分享一个开源小工具CAdapt
linux·c·gnu·glibc·kernel·升级·灵感
mounter6257 小时前
Linux 内核热升级(Live Update)技术详解:PCI、VFIO 与 IOMMU 子系统的演进与实战解析引言
linux·linux kernel·kernel·iommu·vfio
砚凝霜7 小时前
【软考信息安全】第十九章 Unix/Linux安全分析与防护
linux·安全·unix
creator_Li8 小时前
Linux 的 Page Cache
linux·page cache