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

Jim*_*imm 60 linux io

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

如果说,我有一个3个缓冲区的向量,我可以使用readv,或者我可以使用单个缓冲区,其大小为3个缓冲区并且可以fread.

因此,我很困惑:应该使用分散/聚集哪些情况以及何时应该使用单个大缓冲区?

Arj*_*kar 95

通过提供的主要便利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();
Run Code Online (Sandbox Code Playgroud)

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

如果你使用,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);
Run Code Online (Sandbox Code Playgroud)

资料来源:

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

  • 在"Linux系统编程"一书中,他们说`readv或writev可以遇到read()和write()系统调用的任何错误,并且在收到这样的错误后,会设置相同的errno代码.所以readv会这样做返回`EINTR`?或者在readv的原子读取之间发生的信号会发生什么?它会被忽略或排队. (3认同)