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


69

分散收集(即readvwritev)中,Linux读入多个缓冲区,并从多个缓冲区进行写操作。

如果说,我有3个缓冲区的向量,我可以使用readv,或者我可以使用单个缓冲区,这是3个缓冲区的组合大小,并且可以做到fread

因此,我感到困惑:在哪些情况下应使用分散/聚集功能,何时应使用单个大缓冲区?

Answers:


104

通过提供的主要便利readvwritev是:

  1. 它允许处理非连续的数据块。即缓冲器需要是一个阵列的一部分,但单独分配。
  2. I / O是“原子的”。即,如果执行a 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,则必须在以下选项之间进行选择:

  1. 使用memcpy(开销)将它们复制到一个内存块中,然后进行一次write调用。然后,写入将是原子的。
  2. 分别对write(开销)进行三个调用。同样,write来自其他进程的调用会散布在这些写操作之间(不是原子的)。

如果writev改用它,那么一切都很好:

  1. 您只进行一个系统调用,而没有memcpy进行这三个系统中的单个缓冲区。
  2. 同样,三个缓冲区以原子方式写入,作为一个块写入。也就是说,如果其他进程也进行写操作,则这些写操作将不会出现在三个向量的写操作之间。

因此,您将执行以下操作:

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);

资料来源:

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

3
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.那么读书会回来EINTR吗?或在readv的原子读取之间发生的信号将发生什么?它会被忽略还是排队。
nmxprime 2014年

@nmxprime如果信号在readv()或期间到达writev(),则这些系统调用(取决于SA_RESTART)将返回少于请求的字节数。
socketpair

我可以不连续的方式而不是整个块将不连续的缓冲区写入文件吗?
Shubham Pendharkar '16

@Shubham什么是“非连续缓冲区”?还是说“非连续缓冲区”?通过“非连续方式”将它们写入文件意味着什么?需要明确的是:“不连续”的字典定义是:“紧密接近,没有实际接触;接近。 ”。
ArjunShankar '16

使用writev与带有“ MSG_MORE”标志的发送之间有什么区别?使用writev更少的系统调用+原子写入是否更有益?
bgura
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.