Подтвердить что ты не робот

Как ускорить создание FileStream

Моему приложению нужно открыть много маленьких файлов, скажем, 1440 файлов, каждый из которых содержит данные за 1 минуту, чтобы прочитать все данные определенного дня. Каждый файл имеет всего пару килобайт. Это для графического приложения, поэтому я хочу, чтобы пользователь (== me!) Не должен был ждать слишком долго.

Оказывается, что открытие файлов происходит довольно медленно. После исследования большинство времени тратится впустую на создание FileStream (OpenStream = новый FileStream) для каждого файла. Пример кода:

// stream en reader aanmaken
FileStream OpenStream;
BinaryReader bReader;

foreach (string file in files)
{
    // bestaat de file? dan inlezen en opslaan
    if (System.IO.File.Exists(file))
    {
        long Start = sw.ElapsedMilliseconds;

        // file read only openen, anders kan de applicatie crashen
        OpenStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

        Tijden.Add(sw.ElapsedMilliseconds - Start);

        bReader = new BinaryReader(OpenStream);

        // alles in één keer inlezen, werkt goed en snel
        // -bijhouden of appenden nog wel mogelijk is, zonodig niet meer appenden
        blAppend &= Bestanden.Add(file, bReader.ReadBytes((int)OpenStream.Length), blAppend);

        // file sluiten
        bReader.Close();
    }
}

Используя таймер секундомера, я вижу, что большинство ( > 80%) времени тратится на создание FileStream для каждого файла. Создание BinaryReader и фактическое чтение файла (Bestanden.add) занимает почти нет времени.

Я озадачен этим и не могу найти способ ускорить его. Что я могу сделать, чтобы ускорить создание FileStream?

обновите вопрос:

  • это происходит как на окнах 7, так и на окнах 10
  • файлы являются локальными (на диске SSD)
  • есть только 1440 файлов в каталоге
  • странно, снова прочитав (то же) файлы, создание FileStreams внезапно обошлось почти безрезультатно. Где-то ОС вспоминая филе.
  • даже если я закрою приложение и перезапустил его, открытие файлов "снова" также почти не требует времени. Это затрудняет поиск проблема производительности. Мне пришлось сделать много копий каталога, чтобы воссоздайте проблему снова и снова.
4b9b3361

Ответ 1

Как вы упомянули в комментарии к вопросу FileStream, сначала считывается 4K для буфера, создавая объект. Вы можете изменить размер этого буфера, чтобы отобразить лучший размер ваших данных. (Уменьшите, если ваши файлы меньше, чем буфер, например). Если вы читаете файл последовательно, вы можете дать OS подсказку об этом через FileOptions. Кроме того, вы можете избежать BinaryReader, потому что вы полностью читаете файлы.

    // stream en reader aanmaken
    FileStream OpenStream;

    foreach (string file in files)
    {
        // bestaat de file? dan inlezen en opslaan
        if (System.IO.File.Exists(file))
        {
            long Start = sw.ElapsedMilliseconds;

            // file read only openen, anders kan de applicatie crashen
            OpenStream = new FileStream(
                file,
                FileMode.Open,
                FileAccess.Read,
                FileShare.ReadWrite,
                bufferSize: 2048, //2K for example 
                options: FileOptions.SequentialScan);

            Tijden.Add(sw.ElapsedMilliseconds - Start);

            var bufferLenght = (int)OpenStream.Length;
            var buffer = new byte[bufferLenght];
            OpenStream.Read(buffer, 0, bufferLenght);

            // alles in één keer inlezen, werkt goed en snel
            // -bijhouden of appenden nog wel mogelijk is, zonodig niet meer appenden
            blAppend &= Bestanden.Add(file, buffer, blAppend);
        }
    }

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

    //the buffer should be bigger than the biggest file to read
    var bufferLenght = 8192;
    var buffer = new byte[bufferLenght];

    foreach (string file in files)
    {
        //skip 
        ...
        var fileLenght = (int)OpenStream.Length;
        OpenStream.Read(buffer, 0, fileLenght);

        blAppend &= Bestanden.Add(file, /*read bytes from buffer */, blAppend);

Надеюсь, это поможет.

Ответ 2

Отказ от ответственности: этот ответ - это просто (основанная) предпосылка, что это скорее ошибка Windows, чем что-то, что вы можете исправить с помощью другого кода.

Таким образом, это поведение может относиться к описанной здесь ошибке Windows: "24-ядерный процессор и я не могу переместить мою мышь" .

Эти процессы все освобождали блокировку из NtGdiCloseProcess.

Поэтому, если FileStream использует и удерживает такую ​​критическую блокировку в ОС, он будет ждать несколько μSec для каждого файла, который будет складываться для тысяч файлов. Это может быть иная блокировка, но вышеупомянутая ошибка, по крайней мере, добавляет возможность аналогичной проблемы.

Чтобы доказать или опровергнуть эту гипотезу, потребуется некоторое глубокое знание о внутренней работе ядра.

Ответ 3

Для данных небольшого размера Вместо использования нескольких файлов используйте одну SQLite базу данных: https://www.sqlite.org

Другим решением является объединение всех файлов в один файл или один ZIP файл.