Почему read() медленнее, чем getc()?

Почему read() медленнее, чем getc()?

Почему readмедленнее, чем getc?

Например, это:

for (;;) {
        chr++;
        amr=read(file1, &wc1, 1);
        amr2=read(file2, &wc2, 1);
        if (wc1 == wc2) {
            if (wc1 == '\n')
                line++;
            if (amr == 0) {
                if (eflg)
                    return (1);
                return (0);
            }
            continue;
        }

медленнее, чем это:

for (;;) {
    chr++;
    c1 = getc(file1);
    c2 = getc(file2);
    if (c1 == c2) {
        if (c1 == '\n')
            line++;
        if (c1 == EOF) {
            if (eflg)
                return (1);
            return (0);
        }
        continue;
    }

getcиспользует readсистемный вызов, так почему же он медленнее?

решение1

Поскольку getc() буферизует считанные данные перед их возвратом, поэтому вызов getc()не обязательно приводит к вызову read(). read()— это системный вызов, который занимает гораздо больше времени, чем обычный вызов функции, поскольку у ядра больше операций для выполнения. Когда вы входите в пространство ядра, он изменяет ваш стек, сохраняет весь контекст, обрабатывает прерывания для маскировки, а на другом конце, когда он завершается, он восстанавливает контекст, прерывания, возвращает ваш стек пользовательского пространства обратно... Вот почему getc() предпочтительнее, потому что он экономит вам важные накладные расходы, если у вас уже есть доступные буферизованные данные.

решение2

Все сводится к тому, что чтение с дисков ориентировано на блоки: чтобы прочитать один байт с диска, оборудование в конечном итоге считывает блок (512 или 1024 или какое-то число) байтов, буферизует все это, передает ядру. Если вы читаете байт 0 файла из блока 0 файла, выполняете некоторую работу, затем читаете байт 1 из файла, ядро, вероятно, снова считывает блок 0 файла. И снова для байта 2, и снова для байта 3. Да, есть потенциальное кэширование, как в ядре, так и в самом диске, но ядро ​​обрабатывает много процессов, так что, возможно, и нет.

Каждый read()вызов также должен изменить состояние ЦП из состояния пользователя в состояние ядра. Как минимум, меняются отображения памяти. Вероятно, происходит много других не столь очевидных вещей. Это тоже может занять время.

Системный read()вызов изменяет состояние ЦП и может повлечь за собой дисковый ввод-вывод. getc()может буферизировать целый блок диска (или больше) в пользовательском пространстве, поэтому, возможно, 512 вызовов заставят getc()ядро ​​прочитать один блок диска с одним изменением состояния. Если вы посмотрите, stdio.hто найдете макрос для константы BUFSIZ, которая должна быть эффективным (диск-блок-множество) размером для read()или write()системный вызов файла на диске.

Связанный контент