Bezdepbonusu7Программирование: статьи и ответы

Вопрос

FileStream очень медленный при холодном запуске приложения

Автор вопроса: Alex KОтветов: 5

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

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

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

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

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

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

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

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

Спасибо.

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

  • Я наблюдаю точно такое же поведение. Использование ReadAllBytes и вычисление хэша занимает короткое время, но может быть ужасным в памяти (в зависимости от размера файла). Поэтому я попытался передать FileStream в вычисление хэша MD5 ($stream) и увидел совершенно неприемлемые результаты. Время результата отличается на порядки... thepip3r 28.03.2014
  • @Alex K: просмотрев FileStream источник похоже, что существует множество директив препроцессора, и даже в самых простых путях инициализация кажется довольно сложной. Вы можете указать, с каким именно конструктором у вас возникли проблемы и как выглядит ваша среда, и, надеюсь, люди (намного) умнее меня смогут вам помочь. Griswald_911 03.08.2018
  • Вы правильно используете многопоточность? Да, шпиндели ограничены, но при доступе к большому количеству небольших файлов один за другим вы можете потратить большую часть времени на ожидание данных, и вы МОЖЕТЕ немного ускорить это (или больше в SSD), используя многопоточность. Не экстремально, но 2-3 потока МОГУТ помочь сократить время простоя. TomTom 06.08.2018
  • Нужно больше информации. Как именно вы вызываете конструктор? Каковы ваши аргументы и как они выглядят? Абсолютный путь или относительный путь? Вы разрабатываете свою программу для уменьшения/устранения накладных расходов JIT? Вы работаете в сценарии с ограниченным доверием или ваше приложение имеет полное доверие? Вы пытались открыть файл с помощью FileOptions.SequentialScan? Вы пытались включить многоядерный jit через ProfileOptimization.StartProfile? antiduh 06.08.2018
  • @antiduh все, что занимает 10 секунд, очевидно, не является функцией этих параметров, а является ошибкой, которую я не ожидаю исправить. ExercisingMathematician 07.08.2018
  • @DanielDonnelly - Вы отвечаете на вопрос, который не был задан. Вы не постер, и постер не указал, что у них проблема с 10-секундными задержками; их задержка составляет 50 мс. Пожалуйста, не пытайтесь изменить тему вопроса другого автора; вместо этого спросите у себя. Если у вас возникли проблемы с задаванием собственных вопросов из-за низкой репутации, я могу предложить вам прочитать справочный центр о том, как задавать продуктивные вопросы. antiduh 07.08.2018

windowsperformancehard-drive

Ответы

Ответ 1 · рейтинг 3 · Community

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

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

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

Ответ 2 · рейтинг 1 · Joe

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

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

Ответ 3 · рейтинг 1 · displayName

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

Кэширование


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

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

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

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

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


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

Ответ 4 · рейтинг 1 · Yennefer

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

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

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

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

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

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

Ответ 5 · рейтинг -1 · Shay Erlichmen

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы