web-dev-qa-db-fra.com

Linux: Quand utiliser scatter / rassembler IO (readv, writev) vs un grand tampon avec fread

Dans scatter et rassembler (c'est-à-dire readv et writev), Linux lit dans plusieurs tampons et écrit à partir de plusieurs tampons.

Si disons, j'ai un vecteur de 3 tampons, je peux utiliser readv, OR je peux utiliser un seul tampon, qui est de taille combinée de 3 tampons et faire fread.

Par conséquent, je suis confus: pour quels cas la diffusion/collecte doit-elle être utilisée et quand utiliser un seul grand tampon?

58
Jimm

La principale commodité offerte par readv, writev est:

  1. Il permet de travailler avec des blocs de données non contigus. c'est-à-dire que les tampons doivent ne pas faire partie d'un tableau, mais être alloués séparément.
  2. L'E/S est "atomique". c'est-à-dire que si vous faites un writev, tous les éléments du vecteur seront écrits en une seule opération contiguë, et les écritures effectuées par d'autres processus ne se produiront pas entre eux.

par exemple. disons, vos données sont naturellement segmentées et proviennent de différentes sources:

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

Maintenant, les trois 'tampons' ne sont pas un gros bloc contigu. Mais vous voulez les écrire de manière contiguë dans un fichier, pour une raison quelconque (disons par exemple, ce sont des champs dans un en-tête de fichier pour un format de fichier).

Si vous utilisez write, vous devez choisir entre:

  1. En les copiant dans un bloc de mémoire en utilisant, par exemple, memcpy (surcharge), suivi d'un seul appel write. L'écriture sera alors atomique.
  2. Faire trois appels distincts à write (frais généraux). De plus, les appels write provenant d'autres processus peuvent se propager entre ces écritures (non atomiques).

Si vous utilisez writev à la place, tout va bien:

  1. Vous effectuez exactement un appel système et aucun memcpy pour créer un seul tampon à partir des trois.
  2. En outre, les trois tampons sont écrits de manière atomique, comme une écriture de bloc. c'est-à-dire que si d'autres processus écrivent également, alors ces écritures n'interviendront pas entre les écritures des trois vecteurs.

Vous feriez donc quelque chose comme:

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

Sources:

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