Подтвердить что ты не робот

Почему функция fwrite libc быстрее, чем функция записи в syscall?

После предоставления той же программы, которая считывает случайный сгенерированный входной файл и перекликается с той же строкой, которую он читает на выходе. Единственное различие заключается в том, что с одной стороны я предоставляю методы чтения и записи из системных вызовов linux, а с другой стороны я использую fread/fwrite.

Сроки ввода моего приложения с размером 10 Мб и повторением его /dev/null, и убедитесь, что файл не кэширован, я обнаружил, что libc fwrite быстрее по шкале LARGE при использовании очень маленьких буферов ( 1 байт в случае).

Вот мой вывод со времени, используя fwrite:

real    0m0.948s
user    0m0.780s
sys     0m0.012s

И используя команду syscall write:

real    0m8.607s
user    0m0.972s
sys     0m7.624s

Единственная возможность, о которой я могу думать, это то, что внутренний libc уже выполняет буферизацию моего ввода... К сожалению, я не мог найти такую ​​информацию в Интернете, поэтому, возможно, гуру здесь могут помочь мне.

4b9b3361

Ответ 1

Сроки моего приложения с вводом Размер 10 Мб и эхо его /dev/null, и убедитесь, что файл в не кэшированный, я обнаружил, что libc Скорее всего, стрелка больше по шкале LARGE, когда используя очень маленькие буферы (1 байт в случай).

fwrite работает в потоках, которые буферизуются. Поэтому многие небольшие буферы будут быстрее, потому что он не будет запускать дорогостоящий системный вызов до тех пор, пока буфер не заполнит (или вы его не закроете или не закроете). С другой стороны, небольшие буферы, отправляемые на write, будут запускать дорогостоящий системный вызов для каждого буфера - там, где вы теряете скорость. С буфером потока 1024 байта и записью 1 байтовых буферов вы смотрите на вызовы 1024 write для каждого килобайта, а не 1024 fwrite вызовов, превращающихся в один write - см. Разницу?

Для больших буферов разница будет мала, потому что будет меньше буферизации и, следовательно, более последовательное количество системных вызовов между fwrite и write.

Другими словами, fwrite(3) - это просто библиотечная процедура, которая собирает вывод в куски, а затем вызывает write(2). Теперь write(2) - системный вызов, который ловушки в ядре. Это то, что происходит на самом деле. Есть некоторые накладные расходы для простого вызова в ядро, а затем есть время, которое требуется, чтобы написать что-то. Если вы используете большие буферы, вы обнаружите, что write(2) работает быстрее, потому что в конечном итоге его нужно вызвать в любом случае, и если вы пишете один или несколько раз на fwrite, тогда накладные расходы на флериту будут такими: больше накладных расходов.

Если вы хотите больше узнать об этом, вы можете посмотреть этот документ, который объясняет стандартные потоки ввода-вывода.

Ответ 2

write (2) является основной операцией ядра.

fwrite (3) - это библиотечная функция, которая добавляет буферизацию поверх write (2).

Для небольших (например, строк по времени) байтов счетчик fwrite (3) быстрее из-за накладных расходов, просто выполняющих вызов ядра.

Для больших байтов байтов ввода-вывода write (2) выполняется быстрее, потому что он не беспокоит буферизацию, и вы должны вызывать ядро ​​в обоих случаях.

Если вы посмотрите на источник на cp (1), вы не увидите никакой буферизации.

Наконец, последнее соображение: ISO C vs Posix. Буферизованные функции библиотеки, такие как fwrite, указаны в ISO C, тогда как вызовы ядра, такие как write, являются Posix. Хотя многие системы требуют Posix-совместимости, особенно при попытке получить право на государственные контракты, на практике это специфично для Unix-подобных систем. Таким образом, буферизованные операционные системы более переносимы. В результате Linux cp, безусловно, будет использовать write, но программа C, которая должна работать на межплатформенной платформе, возможно, должна использовать fwrite.

Ответ 3

Вы также можете отключить буферизацию с помощью функции setbuf(). Когда буферизация отключена, fwrite() будет медленнее, чем write(), если не медленнее.

Более подробную информацию по этому вопросу можно найти здесь: http://www.gnu.org/s/libc/manual/html_node/Controlling-Buffering.html