Direct I/O and Buffered I/O

直接I/O(Direct I/O)和缓冲I/O(Buffered I/O)是计算机系统中处理输入/输出操作两种不同的方法。它们在数据传输的方式、效率以及使用缓冲区的方式上有所区别。

缓冲I/O(Buffered I/O)

在缓冲I/O的方式下,内核维护一个缓冲区。写文件时,数据从用户空间缓冲区复制到内核缓冲区即可返回。内核缓冲区填满后,再把数据从内核缓冲区送到驱动程序缓冲区中。

缓冲I/O的优点:

        将多个小的写聚合在一起一次性写入外设,减少和外设交互的次数;

        程序员不需要知道设备的细节(看直接I/O的使用方式就明白了)。

缓冲I/O的缺点:

        数据拷贝开销;

        内核缓冲区占用内核空间;

        如果突然断电,在应用程序的视角下,数据可能丢失(明明write已经返回了,但是加电重启之后发现数据竟然没有保存到文件中)。

直接I/O(Direct I/O)

在直接I/O的方式下,没有内核缓冲区。写文件时,数据直接从用户空间缓冲区传输到内核驱动程序的缓冲区。

直接I/O的优点:

        不经过内核缓冲区,相比缓冲I/O没有那么大的数据拷贝开销;

        数据丢失的风险比缓冲I/O小。

直接I/O的缺点:

        需要应用程序对齐设备的边界,否则读写操作会报错;

        每次读写都直接和设备交互,如果频繁地和设备交互,可能影响性能。

对齐设备的块边界,成功创建了一个文件并向其中写入8KB数据:

 

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>


//在我的主机上,标准文件里面没有定义宏O_DIRECT,因此需要自己写代码定义
#ifndef O_DIRECT    
#define O_DIRECT 040000
#endif

//我主机上的存储设备是NVMe SSD,块大小是4KB。块大小是存储设备的一项参数,需要使用专门的工具查询
#define BLOCK_SIZE 4096
#define BUFFER_SIZE (BLOCK_SIZE * 2) // 分配一个缓冲区,它的大小和块大小对齐

int main() {
    int fd;
    char *buffer;
    ssize_t bytes_written;
    const char *data = "hello world!";

    // 分配一个对齐的缓冲区
    if (posix_memalign((void **)&buffer, BLOCK_SIZE, BUFFER_SIZE) != 0) {
        perror("posix_memalign");
        return 1;
    }

    // 清零缓冲区
    memset(buffer, 0, BUFFER_SIZE);

    // 将数据复制到缓冲区的开始处
    memcpy(buffer, data, strlen(data) + 1);

    // 打开文件,使用O_DIRECT标志
    fd = open("example.txt", O_WRONLY | O_CREAT | O_DIRECT, S_IRUSR | S_IWUSR);
    if (fd < 0) {
        perror("open");
        free(buffer);
        return 1;
    }

    // 使用write执行直接IO写入操作
    bytes_written = write(fd, buffer, BUFFER_SIZE);
    if (bytes_written < 0) {
        perror("write");
        close(fd);
        free(buffer);
        return 1;
    }

    // 关闭文件
    close(fd);
    free(buffer);

    return 0;
}

程序运行后,生成8KB大小的文件

使用vim打开:

 未对齐块边界,只写入30B。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>



#ifndef O_DIRECT
#define O_DIRECT 040000
#endif

#define BLOCK_SIZE 4096
#define BUFFER_SIZE (BLOCK_SIZE * 2) // 分配一个足够大的缓冲区

int main() {
    int fd;
    char *buffer;
    ssize_t bytes_written;
    const char *data = "hello world!";

    // 分配一个对齐的缓冲区
    if (posix_memalign((void **)&buffer, BLOCK_SIZE, BUFFER_SIZE) != 0) {
        perror("posix_memalign");
        return 1;
    }

    // 清零缓冲区
    memset(buffer, 0, BUFFER_SIZE);

    // 将数据复制到缓冲区的开始处
    memcpy(buffer, data, strlen(data) + 1);

    // 打开文件,使用O_DIRECT标志
    fd = open("example.txt", O_WRONLY | O_CREAT | O_DIRECT, S_IRUSR | S_IWUSR);
    if (fd < 0) {
        perror("open");
        free(buffer);
        return 1;
    }

    // 使用pwrite执行直接IO写入操作
    bytes_written = write(fd, buffer, 30);
    //bytes_written = pwrite(fd, buffer, strlen(data) + 1, 0);
    if (bytes_written < 0) {
        perror("write");
        close(fd);
        free(buffer);
        return 1;
    }

程序运行时候write会报错:Invalid argument:

这说明直接IO需要程序员考虑很多细底层细节,对编程不是很友好。

未对齐块边界,只是写入30字节,但由于没有用直接I/O的模式打开文件,因此可以正常写入。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>



#ifndef O_DIRECT
#define O_DIRECT 040000
#endif

#define BLOCK_SIZE 4096
#define BUFFER_SIZE (BLOCK_SIZE * 2) // 分配一个足够大的缓冲区

int main() {
    int fd;
    char *buffer;
    ssize_t bytes_written;
    const char *data = "hello world!";

    // 分配一个对齐的缓冲区
    if (posix_memalign((void **)&buffer, BLOCK_SIZE, BUFFER_SIZE) != 0) {
        perror("posix_memalign");
        return 1;
    }

    // 清零缓冲区
    memset(buffer, 0, BUFFER_SIZE);

    // 将数据复制到缓冲区的开始处
    memcpy(buffer, data, strlen(data) + 1);

    // 打开文件,如果不使用O_DIRECT标志,那么默认文件使用缓冲I/O
    fd = open("example.txt", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd < 0) {
        perror("open");
        free(buffer);
        return 1;
    }

    // 使用write执行缓冲写入,写入大小为30B
    bytes_written = write(fd, buffer, 30);
    if (bytes_written < 0) {
        //perror("pwrite");
        perror("write");
        close(fd);
        free(buffer);
        return 1;
    }

    // 关闭文件
    close(fd);
    free(buffer);

    return 0;
}

程序运行后,文件的大小为30B。

 

使用vim打开文件example.txt:一共30个字符

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值