Линукс: когда использовать разброс/сборки ввода / вывода (вызовах readv, файлы кеша) против большой буфер с fread
на scatter и собрать (т. е. readv
и writev
), Linux читает в несколько буферов и записывает из нескольких буферов.
если сказать, что у меня есть вектор из 3 буферов, я могу использовать readv
, или я могу использовать один буфер, который имеет общий размер 3 буферов и fread
.
следовательно, я запутался: для каких случаев следует использовать scatter / gather и когда следует использовать один большой буфер?
1 ответ:
основные удобства, предлагаемые
readv
,writev
- это:
- позволяет работать с несмежными блоками данных. т. е. буферы нужны не быть частью массива, но выделено отдельно.
- ввод / вывод является "атомарным". т. е. если вы делаете
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
вызовы из других процессов могут перемежаться между этими записями (не атомарными).если вы используете
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);
источники: