Linux:何时使用分散/收集 IO(readv、writev)与带有 fread 的大缓冲区

Posted

技术标签:

【中文标题】Linux:何时使用分散/收集 IO(readv、writev)与带有 fread 的大缓冲区【英文标题】:Linux: When to use scatter/gather IO (readv, writev) vs a large buffer with fread 【发布时间】:2012-05-18 05:02:16 【问题描述】:

scattergather(即readvwritev)中,Linux 读取多个缓冲区并从多个缓冲区写入。

如果说,我有一个包含 3 个缓冲区的向量,我可以使用 readv,或者我可以使用单个缓冲区,它具有 3 个缓冲区的组合大小并执行 fread

因此,我很困惑:对于哪些情况应该使用分散/聚集,什么时候应该使用单个大缓冲区?

【问题讨论】:

【参考方案1】:

readvwritev提供的主要便利是:

    它允许使用不连续的数据块。即缓冲区需要是数组的一部分,而是单独分配。 I/O 是“原子的”。即如果您执行writev,则向量中的所有元素都将写入一个连续的操作中,其他进程完成的写入不会发生在它们之间。

例如比如说,您的数据是自然分段的,并且来自不同的来源:

struct foo *my_foo;
struct bar *my_bar;
struct baz *my_baz;

my_foo = get_my_foo();
my_bar = get_my_bar();
my_baz = get_my_baz();

现在,所有三个“缓冲区”都不是一个大的连续块。但是无论出于何种原因,您都希望将它们连续写入文件(例如,它们是文件格式的文件头中的字段)。

如果您使用write,您必须在以下选项中进行选择:

    使用memcpy(开销)将它们复制到一个内存块中,然后调用write。然后写入将是原子的。 对write 进行三个单独的调用(开销)。此外,来自其他进程的 write 调用可以散布在这些写入之间(不是原子的)。

如果你改用writev,一切都很好:

    您只进行了一次系统调用,没有memcpy 可以从三个系统调用中创建一个缓冲区。 此外,三个缓冲区是原子写入的,作为一个块写入。即,如果其他进程也写入,则这些写入不会出现在三个向量的写入之间。

所以你会做这样的事情:

struct iovec iov[3];

iov[0].iov_base = my_foo;
iov[0].iov_len = sizeof (struct foo);
iov[1].iov_base = my_bar;
iov[1].iov_len = sizeof (struct bar);
iov[2].iov_base = my_baz;
iov[2].iov_len = sizeof (struct baz);

bytes_written = writev (fd, iov, 3);

来源:

    http://pubs.opengroup.org/onlinepubs/009604499/functions/writev.html http://linux.die.net/man/2/readv

【讨论】:

Linux System Programming 书中,他们说readv or writev can experience any of the errors of the read() and write() system calls, and will, upon receiving such errors, set the same errno codes. 那么readv 会返回EINTR 吗?或者在 readv 的原子读取之间发生的信号会发生什么?它会被忽略还是排队。 @nmxprime 如果信号在readv()writev() 期间到达,这些系统调用(取决于SA_RESTART)将返回比请求更少的字节。 我可以在文件中以非连续的方式而不是整个块的方式写入非连续的缓冲区吗? @Shubham 什么是“非连续缓冲区”?还是您的意思是“不连续的缓冲区”?以“非连续方式”将它们写入文件是什么意思?需要明确的是:“非连续”的字典定义是:“在没有实际接触的情况下非常接近;接近。”。 使用 writev 与使用“MSG_MORE”标志发送有什么区别?使用 writev 是否​​更有益于更少的系统调用 + 原子写入?

以上是关于Linux:何时使用分散/收集 IO(readv、writev)与带有 fread 的大缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

readv 和 writev

分散收集(克隆+聚合)不起作用

有效地收集/分散任务

readv()、writev()、WSARecv()、WSASend()

advio

收集有关 Linux 上的线程调度的信息