Что происходит на низком уровне, когда я вызываю fseek()?

Когда fseek() вызывается в C - или, seek() вызывается для файлового объекта на любом современном языке, таком как Python или Go - что происходит на очень низком уровне?

Что на самом деле делает операционная система или жесткий диск? Что читает? Какие накладные расходы возникают? Как размер блока влияет на эти издержки?

Изменить, чтобы добавить:

Учитывая NTFS с размером блока 4 КБ, вызывает ли поиск 4096 байт меньше затрат ввода-вывода, чем чтение 4096 байт?

Второе редактирование:

Если сомневаешься, иди эмпирически.

Использование наивного кода Python с файлом 1,5 ГБ:

Чтение 4096 последовательно: 21,2
Ищите 4096 (относительный): 1,35
Ищите 4096 (абсолют): 0,75 (интересно)
Ищите и читайте каждый третий 4096 (относительный): 21,3
Ищите и читайте каждый третий 4096 (абсолютный): 21,5

Время усредняется в секундах. Аппаратное обеспечение представляет собой неописуемый ПК с диском SATA под управлением Windows XP.

Это было очень разочаровывающим. У меня есть несколько ГБ файлов, которые я должен читать почти постоянно. Около 66% блоков размером 4 КБ в файлах неинтересны, и я заранее знаю их смещение.

Первоначально я думал, что это может быть большой победой, чтобы переписать унаследованный код, поскольку теперь он последовательно читает 4096 байт за раз через файлы. Предполагая, что Win32 Python не сломан каким-то фундаментальным образом, включение поиска не имеет преимущества для неслучайных чтений.

1 ответ

Это сильно зависит от текущих условий. Как правило, fseek() только изменяет состояние потока (либо устанавливает текущую позицию, либо возвращает ошибку, если параметры неверны). Но - fseek() очищает буфер, что может привести к отложенной операции записи. Если файл является файлом UTF8 и перевод включен, ftell(), вызванная из fseek (), должна прочитать эту часть файла, чтобы правильно рассчитать смещение. Если трансляция CRLF включена, также выполняются операции чтения. Но в случае простого бинарного файла и отсутствия ожидающей операции записи fseek () просто устанавливает позицию в потоке и не требует перехода на более низкий уровень. Для получения дополнительной информации см. Исходный код CRT.

Другие вопросы по тегам