Linux: Когда использовать разброс/сборку IO (readv, writev) против большого буфера с fread

В разбросе и сборе (т.е. readv и writev), Linux читает несколько буферов и записывает их из нескольких буферов.

Если, скажем, у меня есть вектор из 3 буферов, я могу использовать readv, ИЛИ я могу использовать один буфер, который имеет смешанный размер из 3 буферов и делает fread.

Следовательно, я запутался: для каких случаев следует использовать рассеяние/сбор и когда должен использоваться один большой буфер?

Ответ 1

Основное удобство, предлагаемое readv, writev:

  • Он позволяет работать с несмежными блоками данных. то есть буферы не должны быть частью массива, но отдельно распределены.
  • 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();

Теперь все три "буфера" не являются одним большим смежным блоком. Но вы хотите написать их смежно в файл по любой причине (скажем, например, это поля в заголовке файла для формата файла).

Если вы используете write, вам нужно выбрать между:

  • Скопируйте их в один блок памяти, используя, скажем, memcpy (служебные данные), а затем один вызов write. Тогда запись будет атомарной.
  • Выполнение трех отдельных вызовов write (служебных данных). Кроме того, write вызовы из других процессов могут пересекаться между этими write (not atomic).

Если вы используете writev вместо этого, все это хорошо:

  • Вы делаете ровно один системный вызов, а не memcpy, чтобы сделать один буфер из трех.
  • Кроме того, три буфера записываются атомарно, поскольку один блок записывает. т.е. если другие процессы также записывают, то эти записи не будут входить между записью трех векторов.

Итак, вы бы сделали что-то вроде:

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

Источники: