除了 stdio 缓冲这一方式外, 分散聚集 IO(Scatter-Gather IO) 也是减少系统调用次数从而
提高系统性能的一种方式。 分散聚集 IO(Scatter-Gather IO) 是一种 IO 操作方式, 它可以在一
次 IO 操作中对多个缓冲区进行读取或写入, 而无需对每个缓冲区进行单独的 IO 操作。
在 Scatter-Gather IO 中, 数据被分散到多个缓冲区中, 每个缓冲区都有一个指针来指示读
写操作的位置。 因此, 使用 Scatter-Gather IO 可以实现高效的数据传输, 同时减少了数据拷贝
的次数和开销, 从而提高了系统性能和效率。
Scatter-Gather IO 通常用于处理大量的数据传输和网络通信, 例如传输文件、 数据库操作
和网络数据包的处理等。 在操作系统中, Scatter-Gather IO 由多个操作系统调用组成, 最常用
的是 readv()和 writev()系统调用, 它们可以同时处理多个缓冲区的数据。
readv()函数和 writev()函数的原型如下:
#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
readv()函数和 writev()函数分别从指定的文件描述符 fd 读取和写入数据, 并将数据分散到
多个缓冲区中。 readv()函数和 writev()函数的参数含义如下所示:
参数名称 | 参数含义 | |
1 | fd | 文件描述符 |
2 | iov | 指向iovce结构体数组的指针,该结构体包含了缓冲区的地址和大小等信息。 |
3 | iovcnt | iovce结构体数组的长度。 |
iovec 结构体定义在头文件<sys/uio.h>中, 其定义如下
struct iovec {
void *iov_base; // 缓冲区基址
size_t iov_len; // 缓冲区长度
};
在分散聚集 IO(Scatter-Gather IO) 的操作中, 使用 iovec 结构体描述每个缓冲区的基址和
长度, 将多个缓冲区组合成一个整体进行 IO 操作。
实例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/uio.h>
#define BUF_SIZE 100
int main()
{
// 定义三个缓冲区
char buf1[BUF_SIZE] = { 0 };
char buf2[BUF_SIZE] = { 0 };
char buf3[BUF_SIZE] = { 0 };
// 定义一个 iovec 结构体数组
struct iovec iov[3];
// 定义一个变量用于记录读取的字节数
ssize_t nread;
// 设置 iovec 结构体数组的各个成员的指针和长度
iov[0].iov_base = buf1;
iov[0].iov_len = 5;
iov[1].iov_base = buf2;
iov[1].iov_len = 8;
iov[2].iov_base = buf3;
iov[2].iov_len = BUF_SIZE;
// 从标准输入中读取数据并写入到 iovec 结构体数组中
nread = readv(STDIN_FILENO, iov, 3);
// 输出读取的字节数
printf("%ld bytes read.\n", nread);
// 分别输出三个缓冲区的内容
printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);
printf("buf3: %s", buf3);
return 0;
}
代码中定义了三个不同大小的缓冲区 buf1、 buf2、 buf3, 并创建了一个 iovec 结构体数组
iov, 将缓冲区的基址和长度保存到数组中。
在 readv 函数中, 将标准输入文件描述符(STDIN_FILENO) 作为第一个参数, 将 iovec 结构体数组 iov 作为第二个参数, 并将数组长度 3 作为第三个参数。 readv 函数将从标准输入中
读取数据, 并将数据分别存储到 iovec 结构体数组 iov 中的三个缓冲区中。
在 writev 函数中, 将标准输出文件描述符(STDOUT_FILENO) 作为第一个参数, 将 iovec
结构体数组 iov 作为第二个参数, 并将数组长度 3 作为第三个参数。 writev 函数将从 iovec 结
构体数组 iov 中的三个缓冲区中读取数据, 并将数据分别写入到标准输出中。