Как размер аргумента области памяти в read () и write () влияет на производительность ввода-вывода? - PullRequest
1 голос
/ 28 мая 2019

Существует пример ввода-вывода из Advanced Programming in Unix Environment :

#include "apue.h"
#define BUFFSIZE 4096
int
main(void)
{
    int  n;
    char  buf[BUFFSIZE];
    while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
    if (write(STDOUT_FILENO, buf, n) != n)
    err_sys("write error");
    if (n < 0)
    err_sys("read error");
    exit(0);
}

Все обычные системные оболочки UNIX предоставляют способ открыть файл для чтения на стандартном вводеи создать (или перезаписать) файл на стандартном выходе и позволить пользователю воспользоваться преимуществами средств перенаправления ввода / вывода оболочки.

На рисунке 3.6 показаны результаты чтения 516 581 760-байтового файла с использованием 20разные размеры буфера, со стандартным выводом, перенаправленным на / dev / null.Файловая система, использованная для этого теста, была ext4-файловой системой Linux с блоками размером 4096 байт.(Значение st_blksize равно 4096). Это объясняет минимум системного времени, возникающий при нескольких измерениях времени, начиная с BUFFSIZE, равного 4096.Увеличение размера буфера выше этого предела имеет небольшой положительный эффект.

enter image description here

  1. Как BUFFSIZE влияет на производительностьчтения файла?

    Когда BUFFSIZE увеличивается до 4096, почему производительность улучшается?Когда BUFFSIZE увеличивается выше 4096, почему производительность не имеет существенного улучшения?

  2. Помогает ли буфер ядра (не тот, который buf с размером BUFFSIZE в программе)в производительности, относительно BUFFSIZE?

    Когда BUFFSIZE мало, буфер ядра помогает накапливать небольшие записи, так что для улучшения производительности?

1 Ответ

2 голосов
/ 28 мая 2019

Каждый вызов read() и write() требует системного вызова (для связи с ядром) плюс время для фактического копирования в (или из) пространство памяти ядра.

Сам системный вызов накладывает фиксированные (на вызов) накладные расходы / затраты, в то время как стоимость копирования данных, конечно, пропорциональна количеству данных, которые необходимо скопировать.

Следовательно, если у вас read() / write() очень маленькие буферы, накладные расходы на выполнение системного вызова будут относительно высокими по сравнению с количеством байтов копируемых данных; и поскольку вам придется совершать большое количество вызовов, общее время выполнения будет больше, чем если бы вы делали большие переводы.

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

read() и write() не накапливают небольшие записи вместе, поскольку они представляют собой прямые системные вызовы. Если вы хотите, чтобы небольшие операции чтения / записи были буферизованы таким образом, среда выполнения C предоставляет оболочки fread() и fwrite(), которые сделают это для вас внутри вашего пространства процессов.

...