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

时间:2012-05-09 16:24:48

标签: linux io

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

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

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

1 个答案:

答案 0 :(得分:91)

readvwritev提供的主要便利是:

  1. 它允许使用不连续的数据块。即缓冲区需要是数组的一部分,而是单独分配。
  2. I / O是'原子'。即如果执行writev,向量中的所有元素都将在一个连续的操作中写入,而其他进程完成的写入将不会在它们之间发生。
  3. e.g。比如说,您的数据是自然分段的,来自不同的来源:

    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调用可以在这些写入之间穿插(非原子)。
    3. 如果你使用writev代替它,那就好了:

      1. 您只进行一次系统调用,而没有memcpy从这三次调用中生成一个缓冲区。
      2. 此外,三个缓冲区以原子方式写入,作为一个块写入。即如果其他进程也写入,那么这些写入将不会介于三个向量的写入之间。
      3. 所以你会做类似的事情:

        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