77

スキャッターアンドギャザー(つまりreadv、および)ではwritev、Linuxは複数のバッファーに読み取り、複数のバッファーから書き込みます。

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

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

4

1 に答える 1

114

によって提供される主な便利さreadvは次のwritevとおりです。

  1. これにより、連続していないデータブロックを操作できます。つまり、バッファは配列の一部である必要はありませんが、個別に割り当てられます。
  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つの「バッファ」はすべて1つの大きな連続ブロックではありません。ただし、何らかの理由でそれらを連続してファイルに書き込みたい場合(たとえば、ファイル形式のファイルヘッダーのフィールドである場合)。

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

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

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

  1. 正確に1つのシステムコールmemcpyを作成し、3つから1つのバッファを作成する必要はありません。
  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
于 2012-05-09T17:07:19.550 に答える