FileStream очень медленный при холодном запуске приложения - PullRequest
10 голосов
/ 02 ноября 2009

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

Код, определяющий производительность, состоит из конструктора FileStream (для открытия файла) и хэша SHA1 (реализация платформы .Net). Код является в значительной степени C # версией того, что было задано в вопросе, с которым я связан выше.

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

  • ~ 50мс
  • 80% конструктор FileStream
  • 18% хеш вычислений

Случай 2: Приложение полностью завершено и снова запущено с просьбой вычислить хэш для тех же файлов:

  • ~ 8ms
  • 90% хеш вычислений
  • 8% Конструктор FileStream

Проблема
Мое приложение всегда используется Дело 1 . Никогда не будет предложено пересчитать хэш для файла, который уже был посещен один раз.

Итак, мой шаг по определению скорости - это FileStream Constructor! Что я могу сделать, чтобы ускорить этот вариант использования?

Спасибо.

P.S. Статистика была собрана с помощью профилировщика JetBrains.

Ответы [ 5 ]

3 голосов
/ 06 августа 2018

... но с другим набором целевых файлов.

Ключевая фраза: ваше приложение не сможет использовать кеш файловой системы. Как это было во втором измерении. Информация каталога не может быть получена из ОЗУ, потому что она еще не была прочитана, ОС всегда вынуждена обращаться к диску, и это медленно.

Только лучшее оборудование может ускорить его. 50 мсек - это стандартное время, необходимое для привода шпинделя, 20 мсек - примерно столько, сколько могут работать такие накопители. Время поиска головки считывателя является жестким механическим пределом. Сегодня это легко победить, SSD широко доступен и доступен по цене. Единственная проблема в том, что когда вы к этому привыкли, вы никогда не вернетесь назад:)

1 голос
/ 06 августа 2018

Неправильное предложение, но это то, что я много сделал, и наш анализ был на 30% - 70% быстрее:

Кэширование


Напишите еще один фрагмент кода, который будет:

  • перебрать все файлы;
  • вычислить хеш; и
  • сохранить его в другом index файле.

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

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

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


Я согласен с предложением @ HansPassant использовать SSD для ускорения чтения с вашего диска. Этот ответ и его ответ являются бесплатными. Вы можете реализовать оба способа, чтобы максимизировать производительность.

1 голос
/ 06 августа 2018

Как указывалось ранее, файловая система имеет собственный механизм кэширования, который нарушает ваши измерения.

Однако конструктор FileStream выполняет несколько задач, которые в первый раз стоят дорого и требуют доступа к файловой системе (следовательно, чего-то, чего может не быть в кэше данных). По понятным причинам вы можете взглянуть на код и увидеть, что классы CompatibilitySwitches используются для обнаружения использования подфункции. Вместе с этим классом Reflection интенсивно используется как напрямую (для доступа к текущей сборке), так и косвенно (для защищенных разделов CAS, требований к каналу безопасности). Механизм Reflection имеет свой собственный кэш и требует доступа к файловой системе, когда его собственный кэш пуст.

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

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

Профилирование с использованием нативных символов и / или с отладкой ядра должно дать вам больше знаний.

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

1 голос
/ 02 ноября 2009

Файловая система и / или контроллер диска будут кэшировать недавно использованные файлы / сектора.

Шаг определения скорости - чтение файла, а не создание объекта FileStream, и вполне нормально, что он будет значительно быстрее при втором запуске, когда данные находятся в кеше.

0 голосов
/ 03 ноября 2009

Вы должны попытаться использовать нативный FILE_FLAG_SEQUENTIAL_SCAN, вам придется пинвока CreateFile, чтобы получить ручку и передать ее FileStream

...