Открывать много маленьких файлов в NTFS слишком медленно

Я пишу программу, которая должна обрабатывать множество небольших файлов, скажем тысячи или даже миллионы. Я тестировал эту часть на 500k файлов, и первым шагом было просто перебрать каталог, в котором есть около 45k каталогов (включая подкаталоги подкаталогов и т. Д.), И 500k небольших файлов. Обход всех каталогов и файлов, включая получение размеров файлов и вычисление общего размера, занимает около 6 секунд. Теперь, если я попытаюсь открыть каждый файл во время обхода и немедленно закрыть его, похоже, что он никогда не останавливается. На самом деле, это занимает слишком много времени (часы ...). Поскольку я делаю это в Windows, я попытался открыть файлы с помощью CreateFileW, _wfopen и _wopen. Я ничего не читал и не записывал в файлы, хотя в окончательной реализации мне нужно будет только чтение. Однако я не заметил заметных улучшений ни в одной из попыток.

Интересно, есть ли более эффективный способ открывать файлы с помощью любой из доступных функций, будь то C, C ++ или Windows API, или единственный более эффективный способ - это читать MFT и читать блоки диска напрямую, что я пытаюсь избежать?

Обновление: приложение, над которым я работаю, делает снимки резервных копий с управлением версиями. Таким образом, у него также есть инкрементные резервные копии. Тест с 500 КБ файлов выполняется в огромном репозитории исходного кода для управления версиями, что-то вроде scm. Итак, все файлы не находятся в одном каталоге. Также существует около 45 тысяч каталогов (упомянутых выше).

Таким образом, предлагаемое решение для архивирования файлов не помогает, потому что, когда резервное копирование выполнено, происходит доступ ко всем файлам. Следовательно, я не увижу от этого никакой пользы и даже повлечет за собой некоторую потерю производительности.


person Amy    schedule 08.01.2015    source источник
comment
Помогают ли этот вопрос и ответ? как максимально ускорить создание файла   -  person Petesh    schedule 08.01.2015
comment
Я делаю это на SSD. Иссе с открытием / закрытием файлов   -  person Amy    schedule 08.01.2015
comment
Покажи свой код. Не видя вашего кода. Вполне возможно, что ваш код находится в бесконечном цикле, неправильно вызывает API или, возможно, работает адекватно. Но без вашего кода каждое предложение будет просто предположением или гипотезой. Кроме того, 500 000 файлов - это ОЧЕНЬ много файлов, и я ожидал, что это займет очень много времени. Что вы на самом деле пытаетесь сделать?   -  person selbie    schedule 08.01.2015
comment
Код в порядке. Он не входит в рекурсию и завершается (хотя и через очень долгое время). Он использует FindFirstFile / FindNextFile для просмотра файлов / каталогов. Я просто проводил тест, и оказалось, что открытие / закрытие каждого файла занимает около 5 мс. Вот что я пытаюсь улучшить ...   -  person Amy    schedule 08.01.2015
comment
Кстати, это приложение для резервного копирования, и это один из вариантов использования. Я не могу раскрыть более подробную информацию о приложении, но этот фрагмент кода довольно тривиален, как я описал его ранее.   -  person Amy    schedule 08.01.2015
comment
Насколько я помню, NTFS не любит, чтобы отдельные каталоги содержали огромное количество файлов. Индекс становится большим и фрагментированным. Рассмотрите возможность распределения файлов по поддереву. stackoverflow .com / questions / 197162 /   -  person Adrian McCarthy    schedule 08.01.2015
comment
В этом вопросе также содержится полезная информация: stackoverflow.com/questions/115882/   -  person Adrian McCarthy    schedule 08.01.2015
comment
Конкретный совет от Microsoft по перечислению большого количества небольших файлов в каталоге: support.microsoft.com/kb/ 2539403   -  person Adrian McCarthy    schedule 08.01.2015
comment
@AdrianMcCarthy: NTFS не важно, сколько файлов находится в одном каталоге. Каталог представляет собой B-Tree, доступ к которому всегда осуществляется эффективно. Более вероятно, что _1 _ / _ 2_ не проходит его эффективно. Или драйвер NTFS пытается слишком много буферизовать. KB2539403 - это приложение, хранящее всю информацию о перечислении файлов, а не размер каталога.   -  person wallyk    schedule 08.01.2015
comment
@wallyk: KB2539403 говорит, что когда отдельные папки содержат большое количество файлов (более 50 000 файлов), при перечислении списка файлов могут возникнуть проблемы с производительностью. ... Когда приложение перечисляет содержимое каталога большой папки, NTFS и диспетчеру кеша ставится задача читать и обрабатывать большие объемы метаданных для выполнения перечисления. Да, это абсолютно об отдельных папках с большим количеством файлов.   -  person Adrian McCarthy    schedule 08.01.2015


Ответы (5)


То, что вы пытаетесь сделать, по сути своей сложно сделать эффективно для любой операционной системы. 45 000 подкаталогов требуют большого доступа к диску, независимо от того, как они разделены.

Любой файл размером около 1000 байт считается "большим" с точки зрения NTFS. Если бы существовал способ уменьшить размер большинства файлов данных примерно до 900 байт, можно было бы добиться большей эффективности, если бы данные файла хранились внутри MFT. Тогда получение данных будет не дороже, чем получение временных меток или размера файла.

Я сомневаюсь, что есть способ оптимизировать параметры программы, параметры процесса или даже параметры настройки операционной системы, чтобы приложение работало нормально. Вы столкнетесь с многочасовой работой, если не сможете радикально изменить ее архитектуру.

Одна из стратегий - распределить файлы по нескольким компьютерам, вероятно, тысячам из них, и иметь под-приложение для каждого процесса локальных файлов, передавая любые результаты главному приложению.

Другой стратегией было бы преобразование всех файлов в несколько файлов большего размера, таких как большие файлы .zip, как предлагает @felicepollano, эффективно виртуализируя ваш набор файлов. Произвольный доступ к файлу размером 4000 ГБ по своей природе является гораздо более эффективным и действенным использованием ресурсов, чем доступ к 4 миллиардам файлов размером 1 МБ. Кроме того, перемещение всех данных в подходящий менеджер баз данных (MySQL, SQL Server и т. Д.) Позволит добиться этого и, возможно, даст другие преимущества, такие как простой поиск и легкая стратегия архивирования.

person wallyk    schedule 08.01.2015
comment
500 КБ в вопросе относятся к количеству файлов, а не к их размеру. - person Adrian McCarthy; 08.01.2015
comment
@AdrianMcCarthy: Спасибо, я прочитал его дважды, но все равно ошибся. Я обновил свой ответ. - person wallyk; 09.01.2015

Накладные расходы от 5 до 20 мсек на файл не являются ненормальными для тома NTFS с таким количеством файлов. (На обычном шпиндельном приводе в любом случае нельзя ожидать большего, потому что он находится в том же порядке, что и время поиска головки. С этого момента я предполагаю, что мы имеем дело с оборудованием корпоративного класса, SSD и / или RAID.)

Исходя из моего опыта, вы можете значительно увеличить пропускную способность за счет распараллеливания запросов, т. Е. Использования нескольких потоков и / или процессов. Похоже, что большая часть накладных расходов приходится на поток, система может открыть десять файлов одновременно почти так же быстро, как она может открыть отдельный файл. Я не уверен, почему это так. Возможно, вам придется поэкспериментировать, чтобы найти оптимальный уровень распараллеливания.

Системный администратор также может значительно повысить производительность, скопировав содержимое на новый том, предпочтительно примерно в том же порядке, в котором к ним будет осуществляться доступ. Мне пришлось сделать это недавно, и это сократило время резервного копирования (для тома с примерно 14 миллионами файлов) с 85 часов до 18 часов.

Вы также можете попробовать OpenFileById ( ), который может лучше работать с файлами в больших каталогах, так как он не требует перечисления дерева каталогов. Однако я сам никогда не пробовал, и это может не иметь большого влияния, поскольку каталог, скорее всего, все равно будет кэширован, если вы только что его перечислили.

Вы также можете быстрее перечислить файлы на диске, прочитав их из MFT, хотя это звучит так, как будто это не так. в настоящий момент для вас это узкое место.

person Harry Johnston    schedule 08.01.2015

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

person Felice Pollano    schedule 08.01.2015
comment
Конечно, сам процесс zip должен будет перечислять, открывать и закрывать каждый из файлов, поэтому, если Эми не нужно обрабатывать одни и те же файлы несколько раз, я не понимаю, как это будет быстрее - вы все равно платите цена. - person Adrian McCarthy; 08.01.2015
comment
@AdrianMcCarthy С zip-файлом можно открыть только один файл ОС, и отдельное извлечение полностью в пользовательском пространстве, минуя любые связанные с ядром накладные расходы на открытие / закрытие дескриптора или перечисление каталогов ... таким образом, если zip-файл сам может быть эффективно перечислен / найден (и используя STORE для данных), тогда это может окупиться в данном сценарии. Но в любом случае хотелось бы увидеть тесты :) - person user2864740; 08.01.2015
comment
@ user2864740: Я хочу сказать, что для создания zip-файла вы должны перечислить, открыть и закрыть все те же файлы, к которым Эми сегодня пытается получить доступ напрямую. Если создатель zip не знает трюка, которого не знает Эми, это - в лучшем случае - будет эквивалентно ее решению. - person Adrian McCarthy; 08.01.2015
comment
@AdrianMcCarthy Предположительно zip будет создан заранее, и этот процесс будет выполняться несколько раз (или zip сгенерирован как некоторый фоновый / ночной / вневременной процесс), но если нет .. - person user2864740; 08.01.2015
comment
@ user2864740: Эми описала это приложение как приложение для резервного копирования, поэтому кажется вероятным, что каждый файл нужно посетить ровно один раз, поэтому этап предварительной обработки не кажется выигрышным. - person Adrian McCarthy; 08.01.2015
comment
Вы можете попробовать уменьшить количество файлов (но побольше). Рассматривали ли вы вместо этого хранение данных в какой-либо базе данных sqlite? Или использовать какой-нибудь проиндексированный файл, например GDBM? - person Basile Starynkevitch; 08.01.2015

Вы можете попробовать выполнить один проход для перечисления файлов в структуре данных, а затем открыть и закрыть их на втором проходе, чтобы увидеть, вызывает ли чередование операций конкуренцию.

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

Также проверьте наличие антивирусных программ в вашей системе. Некоторые будут замедлять каждый доступ к файлу, сканируя весь файл каждый раз, когда вы пытаетесь получить к нему доступ. Использование Sysinternals Procmon может помочь вам обнаружить такого рода проблемы.

Пытаясь повысить производительность, рекомендуется поставить перед собой цель. Насколько быстро достаточно быстро?

РЕДАКТИРОВАТЬ: Эта часть исходного ответа неприменима, если вы не используете Windows XP или более раннюю версию:

При открытии и закрытии каждого файла по умолчанию обновляется время последнего доступа в индексе. Вы можете попробовать провести эксперимент, отключив эту функцию через реестр или командная строка и посмотрите, насколько это важно. Я не уверен, возможно ли это сделать в вашем реальном продукте, поскольку это глобальная настройка.

person Adrian McCarthy    schedule 08.01.2015
comment
Я добавил некоторые пояснения в исходный пост. Что касается того, насколько быстро это достаточно быстро, я бы сказал, что сокращение времени до одной пятой (1 мс или меньше на файл) было бы приемлемым. Как я уже упоминал, я мог бы использовать MFT напрямую ... Я просто хочу избежать этого, если возможно - person Amy; 08.01.2015
comment
Последний доступ по умолчанию отключен в современных версиях Windows. (Думаю, начиная с Vista.) - person Harry Johnston; 09.01.2015
comment
@HarryJohnston: Ты прав. Я думал, что его отключение по умолчанию началось в Windows 8, но на самом деле это была Vista. - person Adrian McCarthy; 09.01.2015
comment
Я думаю, что XP была первой версией, в которой была возможность отключить обновление последнего доступа. По умолчанию он кэширует таким образом, что не будет записывать временные метки последнего доступа чаще одного раза в час (которые можно изменить на немедленное обновление). - person wallyk; 10.01.2015

NTFS работает медленно с большим количеством файлов. Особенно, если они находятся в одном каталоге. Когда они разделены на отдельные директории и поддиры, доступ происходит быстрее. У меня есть опыт работы со многими файлами, хранящимися на плате видеокамеры (4 камеры), и это было слишком медленно, даже чтобы увидеть количество файлов и размер (Свойства в корневой папке). Интересно, что когда на диске стоит FAT32, то же самое намного шустрее. И все источники говорят, что NTFS быстрее ... Может быть, быстрее для чтения одного файла, но операции с каталогами медленнее.

Зачем нужно столько файлов? Надеюсь, служба индексации каталогов включена.

person i486    schedule 08.01.2015