77

分散聚集(即readvwritev)中,Linux 读取多个缓冲区并从多个缓冲区写入。

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

因此,我很困惑:对于哪些情况应该使用 scatter/gather 以及何时应该使用单个大缓冲区?

4

1 回答 1

114

readv提供的主要便利writev是:

  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
于 2012-05-09T17:07:19.550 回答