web-dev-qa-db-ja.com

Linux:scatter / gather IO(readv、writev)vs freadの大きなバッファーを使用する場合

scatterおよびgather(つまり、readvおよびwritev)では、Linuxは複数のバッファーへの読み取りと複数のバッファーからの書き込みを行います。

たとえば、3つのバッファーのベクトルがある場合、readvを使用できます。OR 3つのバッファーを組み合わせたサイズの単一のバッファーを使用して、fread

したがって、私は混乱しています:どのケースでスキャッター/ギャザーを使用する必要があり、いつ単一の大きなバッファーを使用する必要がありますか?

58
Jimm

readvwritevが提供する主な利便性は次のとおりです。

  1. 連続していないデータブロックを操作できます。つまり、バッファーはnot配列の一部である必要がありますが、個別に割り当てられます。
  2. I/Oは「アトミック」です。つまり、writevを実行すると、ベクター内のすべての要素が1つの連続した操作で書き込まれ、他のプロセスで行われた書き込みはそれらの間に発生しません。

例えばたとえば、データは自然にセグメント化されており、さまざまなソースからのものです。

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

現在、3つの「バッファ」はすべてnot1つの大きな連続ブロックです。ただし、何らかの理由で(たとえば、ファイル形式のファイルヘッダー内のフィールドであるなど)、ファイルに連続して書き込みたい場合があります。

writeを使用する場合、次のいずれかを選択する必要があります。

  1. たとえば、memcpy(オーバーヘッド)を使用して1つのメモリブロックにコピーし、その後に単一のwrite呼び出しを続けます。その後、書き込みはアトミックになります。
  2. write(オーバーヘッド)を3回個別に呼び出します。また、他のプロセスからのwrite呼び出しは、これらの書き込みの間に散在することがあります(アトミックではありません)。

代わりにwritevを使用する場合、すべて良いです:

  1. システムコールを1つだけ作成し、3つから1つのバッファを作成するmemcpyはありません。
  2. また、3つのバッファーは、1つのブロック書き込みとしてアトミックに書き込まれます。つまり、他のプロセスも書き込む場合、これらの書き込みは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
93
ArjunShankar