1. ホーム
  2. linux

Linuxの場合。散布/収集 IO (readv, writev) と fread によるラージバッファをいつ使うか

2023-08-21 12:56:54

質問

散布 集める (すなわち readvwritev など)、Linuxは複数のバッファに読み込み、複数のバッファから書き込みを行います。

例えば、3つのバッファからなるベクターがあるとすると、そのベクターに対して readv を使うこともできますし、3 つのバッファを結合した単一のバッファを使って fread .

それゆえ、私は混乱しています。どのような場合に scatter/gather を使用し、どのような場合に単一の大きなバッファを使用する必要があるのでしょうか。

どのように解決するのですか?

が提供する主な利便性は readv , writev

  1. 連続しないデータブロックを扱うことができます。つまり、バッファには ではなく は配列の一部である必要はなく、別々に割り当てられるのです。
  2. I/Oは「アトミック」です。 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();

さて、3つの「バッファ」はすべて ではなく でなく、1 つの大きな連続したブロックです。しかし、何らかの理由 (たとえば、ファイル形式のファイル ヘッダーのフィールドであるなど) で、それらをファイルに連続的に書き込みたい場合です。

もしあなたが write のどちらかを選択しなければならない。

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

もしあなたが writev を使えば、すべてうまくいきます。

  1. 正確に1つのシステムコールを行い memcpy の 3 つから 1 つのバッファを作成します。
  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