首页 > linux文件IO与内存映射:分散/聚集IO技术(scatter-gather)

linux文件IO与内存映射:分散/聚集IO技术(scatter-gather)

前言

根据上文我们学习到的用户空间的IO缓冲区,操作系统为了减少系统调用的次数,节省系统开销,提出了用户空间的IO缓冲区,即为用户空间的文件读写开辟一段可以利用setvbuf配置大小的内存空间来作为文件IO缓冲区。


描述

为了在以上IO缓冲区的基础上更进一步得减少系统调用的次数,提出了分散/聚合IO技术,总体上是使用了单个向量的IO操作代替了多个向量的IO操作。

读文多个件的时候将从page cache中读到的内容先读入到一个IO缓冲区数据结构中,再由一个缓冲区分别分散返回到多个文件缓冲区中;写文件的过程与读文件的过程刚好相反,即将多个文件缓冲区的内容聚合写到一个缓冲区中,写入page cache中,从而更高得提升系统调用效率。

在这里插入图片描述

实现

实现scatter-gather技术的系统调用原型如下:

  • 头文件

  • 函数使用:

    ssize_t readv(int fd, const struct iovec *iov, int iovcnt);

    ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

  • 函数参数

    fd :打开的文件描述符

    iov: IO向量数据结构内容如下,每个结构体成员代表一个buffer:

     struct iovec { void  *iov_base;    /* Starting address */size_t iov_len;     /* Number of bytes to transfer */};
    

    iovcnt:IO向量的个数

    这两个系统调用的底层仍然是使用read/write系统调用,只是对IO 缓冲区做了聚合,支持多个IO缓冲区内容聚合到同一个IO向量中

代码如下:

writev.c

#include 
#include 
#include 
#include 
#include 
#include int main(int argc, char *argv[])
{ ssize_t count = 0;int fd, i = 0;char *buf[]={ "buffer1
","buffer2
","buffer3
"};fd = open(argv[1], O_WRONLY|O_CREAT, 0666);if (-1 == fd) { printf("open failed 
");_exit(-1);}//将三个IO缓冲区的文件聚合为一个IO向量struct iovec iov[3];for (i ; i < 3; ++i) { iov[i].iov_base = buf[i];iov[i].iov_len = sizeof(buf[i]) + 1;printf("iovec[%d] size is %ld 
",i,iov[i].iov_len);}//写入一个文件count = writev(fd, iov, 3);if (-1 == count) { printf("writev failed
");_exit(-1);}close(fd);return 0;
}

readv.c

#include 
#include 
#include 
#include 
#include 
#include int main(int argc, char *argv[])
{ ssize_t count = 0;int fd, i = 0;char buf1[9],buf2[9],buf3[9];//生成一个文件,可以传入聚合IO缓冲区的文件fd = open(argv[1], O_RDONLY,0666);if (-1 == fd) { printf("open failed 
");_exit(-1);}//对IO向量中的各个IO缓冲区进行地址和内容大小赋值struct iovec iov[3];iov[0].iov_base = buf1;iov[0].iov_len = sizeof(buf1);	iov[1].iov_base = buf2;iov[1].iov_len = sizeof(buf2);	iov[2].iov_base = buf3;iov[2].iov_len = sizeof(buf3);	//从page cache读入的一个向量会分散到三个缓冲区中count = readv(fd,iov,3);if (-1 == count) { printf("writev failed
");_exit(-1);}for (i ; i < 3; ++i) { printf(" %s",(char *)(iov[i].iov_base));}prinft("buf1 %s
",buf1);prinft("buf2 %s
",buf2);prinft("buf3 %s
",buf3);close(fd);return 0;
}

编译输出如下:

gcc writev.c -o writev

gcc readv.c -o readv

zhang@ubuntu:~/Desktop/cpp_practice$ ./writev  writevfile
iovec[0] size is 9 
iovec[1] size is 9 
iovec[2] size is 9 
zhang@ubuntu:~/Desktop/cpp_practice$ ./readv writevfile buffer1buffer2buffer3
buf1 buffer1buf2 buffer2buf3 buffer3

更多相关:

  • 文章目录先看看性能AIO 的基本实现io_ring 使用io_uring 基本接口liburing 的使用io_uring 非poll 模式下 的实现io_uring poll模式下的实现io_uring 在 rocksdb 中的应用总结参考...

  • 文章目录用户空间IO缓冲区产生IO缓冲区 描述IO缓冲区的写模式自定义IO缓冲区 用户空间IO缓冲区产生 系统调用过程中会产生的开销如下: 切换CPU到内核态进行数据内容的拷贝,从用户态到内核态或者从内核态到用户态切换CPU到用户态 以上为普通到系统调用过程中操作系统需要产生的额外开销,为了提升系统调用的性能,这里推出用...

  • 串口发送部分代码: //通过信号量的方法发送数据 void usart1SendData(CPU_INT08U ch) {OS_ERR err;CPU_INT08U isTheFirstCh;OSSemPend(&Usart1Sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);//阻塞型等待串口发送资...