Как реализуется fseek() в файловой системе?
Это не простой вопрос программирования, но он влияет на производительность программ с помощью fseek(), поэтому важно знать, как это работает. Небольшой отказ от ответственности, чтобы он не закрылся.
Мне интересно, насколько эффективно вставлять данные в середине файла. Предположим, у меня есть файл с данными 1 МБ, а затем я вставляю что-то со смещением 512 КБ. Насколько эффективно это можно сравнить с добавлением моих данных в конце файла? Просто чтобы сделать полный пример, скажем, я хочу вставить 16 Кбайт данных.
Я понимаю, что ответ зависит от файловой системы, однако я предполагаю, что методы, используемые в обычных файловых системах, очень похожи, и я просто хочу получить правильное представление об этом.
Ответы
Ответ 1
(отказ от ответственности: я хочу просто добавить некоторые подсказки к этому интересному обсуждению)
ИМХО есть некоторые вещи, которые нужно учитывать:
1) fseek не является основной системной службой, а библиотечной функцией. Чтобы оценить его производительность, мы должны рассмотреть, как реализуется библиотека потока файлов. В общем случае библиотека ввода-вывода файлов добавляет слой буферизации в пространстве пользователя, поэтому производительность fseek может быть совершенно иной, если целевая позиция находится внутри или за пределами текущего буфера. Кроме того, системные службы, которые использует библиотека I/O, могут сильно различаться. То есть в некоторых системах библиотека, по возможности, широко использует картографию памяти файлов.
2) Как вы сказали, разные файловые системы могут вести себя совсем по-другому. В частности, я ожидал бы, что транзакционная файловая система должна сделать что-то очень умное и, возможно, дорогое, чтобы быть готовым к возможному откату прерванной операции записи в середине файла.
3) Современные ОС имеют очень агрессивные алгоритмы кеширования. Файл "fseeked", скорее всего, уже присутствует в кеше, поэтому операции становятся намного быстрее. Но они могут значительно ухудшиться, если важна общая активность файловой системы, создаваемая другими процессами.
Любые комментарии?
Ответ 2
Предположим, что пример ext2 FS и ОС Linux. Я не думаю, что будет значительная разница в производительности между вставкой и добавлением. В обоих случаях файлы node и таблица смещения должны быть прочитаны, соответствующий сектор диска отображается в память, данные обновлены и в какой-то более поздней момент данные записываются обратно на диск. В этом примере большая разница в производительности - хорошая временная и пространственная локальность при доступе к частям файла, поскольку это уменьшит количество комбайнов load/store.
Как известно, вы можете ускорить обе операции, если у вас есть дело с данными, записывающими точные кратные размеру блока FS, в этом случае вы можете пропустить этап загрузки и просто вставить новые блоки в файлы inode datastrucure. Это было бы непрактично, вам понадобился бы низкий уровень доступа к драйверу FS, и использование его было бы очень ограничительным и не переносимым.
Ответ 3
fseek(...)
- это вызов библиотеки, а не системный вызов ОС. Это библиотека времени выполнения, которая заботится о фактических накладных расходах, связанных с системным вызовом ОС, с технической точки зрения, fseek косвенно делает вызов системе, но на самом деле это не так (это выявляет четкое различие между различия между вызовом библиотеки и системным вызовом). fseek(...)
- стандартная функция ввода-вывода, независимо от базовой системы... однако... и это большая, однако...
ОС, скорее всего, будет кэшировать файл в своей памяти ядра, то есть прямое смещение к местоположению на диске, где хранятся 1 и 0, через уровни ядра ОС, больше, чем вероятно, самый верхний слой в ядре, который будет иметь моментальный снимок того, из чего состоит файл, т.е. данные независимо от того, что он содержит (это все равно, если "указатели" на структуру диска для что смещение к lcoation на диске действительно!)...
Когда fseek(..)
происходит, было бы много чрезмерного, косвенно, ядро делегировало задачу чтения с диска, в зависимости от того, насколько фрагментирован файл, это может быть теоретически "повсюду" ", что может быть значительным перевесом с точки зрения необходимости, с точки зрения пользователя-пользователя, то есть кода C, выполняющего fseek(...)
, он может рассеиваться повсюду, чтобы собрать данные в" один "непрерывный просмотр данных" и впредь, вставляя в середину файла (помните, что на этом этапе ядро должно было бы отрегулировать местоположение/смещения в фактическом диске для данных) будет считаться медленнее, чем добавление к конец файла.
Причина довольно проста: ядро "знает", что было последним смещением, и просто вытирает маркер EOF и вставляет больше данных, за кулисами, ядро, приходится выделять еще один блок памяти для диска -buffer с отрегулированным смещением в положение на диске после маркера EOF, как только добавление данных будет завершено.
Ответ 4
Одно из наблюдений, которое я сделал о fseek
для Solaris, заключается в том, что каждый вызов этого параметра сбрасывает буфер чтения FILE
. Следующее чтение будет всегда читать полный блок (по умолчанию 8K). Поэтому, если у вас есть много произвольного доступа с небольшим количеством считываний, рекомендуется сделать это без буферизации (setvbuf
с буфером NULL
) или даже использовать прямые системные вызовы (lseek
+ read
или даже лучше pread
, которые это только 1 syscall вместо 2). Я полагаю, что подобное поведение будет похоже на другие ОС.
Ответ 5
Вы можете вставлять данные в середину файла эффективно только в том случае, если размер данных является кратным сектору FS, но ОС не предоставляет таких функций, поэтому вам нужно использовать низкоуровневый интерфейс для драйвера FS.
Ответ 6
Вставка данных в середине файла менее эффективна, чем добавление к концу, потому что при вставке вам нужно будет переместить данные после точки вставки, чтобы освободить место для вставленных данных. Перемещение этих данных будет включать их чтение с диска, запись данных, которые нужно вставить, а затем запись старых данных после вставленных данных. Таким образом, при вставке вы должны иметь хотя бы одно дополнительное чтение и запись.