C # Повышение эффективности программы? - PullRequest
3 голосов
/ 09 сентября 2011

Я работаю над программой на C #, которая читает очень большие файлы и проверяет их на наличие различных атрибутов и полей.Я тестировал файлы с менее чем 1 миллионом строк, и он выполнялся, как и ожидалось.Я недавно проверил его на файле с 2,5 миллионами строк, и мне потребовалось 4 часа, чтобы пройти через него.

Я использую пользовательскую функцию чтения для чтения каждого символа, чтобы я мог найти все CR и LF, потому что очень важно, чтобы каждая строка содержала их.Я протестировал функцию чтения по отдельности, и чтение файла занимает около 14 минут, что, на мой взгляд, достаточно разумно, чтобы прочитать каждый символ в 2,5 миллиона строк по 1500 символов.Я включу функцию чтения, однако это не вызывает проблемы.

Моя функция чтения добавляет каждый символ в строку, а затем я проверяю различные значения в строке.Например, является ли длина строки правильной, содержит ли файл заголовок и содержит ли заголовок правильные значения.А также конкретные значения, такие как число символа 403-404, поле 1250-1300 не ноль и т. Д.

Мой вопрос заключается в том, что я могу сделать, чтобы выяснить, что вызывает замедление, и увеличить мойэффективность моей программы?Я попытался проверить время в начале и в конце каждого цикла строки, и оно, похоже, не меняется.Однако каждые 100 000 занимает значительно больше времени, чем предыдущие.Например, обработка строки с 10 000 до 20 000 заняла менее 3 секунд, а с 830 000 до 840 000 - около 35 секунд.Я рассмотрел попытку создания нескольких потоков, но не думаю, что это поможет в моем случае с чтением строк из файла.Мысли?Спасибо за помощь!

    static void ReadMyLine(ref string currentLine, string filePath, ref int asciiValue, ref Boolean isMissingCR, ref Boolean isMissingLF, ref Boolean isReversed, ref StreamReader file)
    {
        Boolean endOfRow = false;
        isMissingCR = false;
        isMissingLF = false;
        isReversed = false;

        currentLine = "";

        while (endOfRow == false)
        {
            asciiValue = file.Read();

            if (asciiValue == 10 || asciiValue == 13)
            {
                int asciiValueTemp = file.Peek();

                if (asciiValue == 13 && asciiValueTemp == 10)
                {
                    endOfRow = true;
                    asciiValue = file.Read();
                }
                else if (asciiValue == 10 && asciiValueTemp == 13)   // CRLF Reversed
                {
                    asciiValue = file.Read();
                    endOfRow = true;
                    isReversed = true;
                }
                else if (asciiValue == 10)                           // Missing CR
                {
                    isMissingCR = true;
                    endOfRow = true;
                }
                else if (asciiValue == 13)                           // Missing LF
                {
                    isMissingLF = true;
                    endOfRow = true;
                }
                else
                    endOfRow = true;
            }
            else if (asciiValue != -1)
                currentLine += char.ConvertFromUtf32(asciiValue);
            else
                endOfRow = true;
        }
    }

1 Ответ

11 голосов
/ 09 сентября 2011

Вот первое, что я искал, и первое, что я бы изменил:

currentLine += char.ConvertFromUtf32(asciiValue);

Не делай этого. Использование конкатенации строк в цикле может убить производительность - сложность O (N 2 ). Вместо этого используйте StringBuilder. См. мою статью о том, когда использовать StringBuilder для более подробного объяснения.

Вполне возможно, что вы можете сделать больше, но просто переход на использование StringBuilder приведет к огромному улучшению:

StringBuilder builder = new StringBuilder();
while (...)
{
    ...
    builder.Append(char.ConvertFromUtf32(asciiValue));
}
currentLine = builder.ToString();

Это также неясно, почему у вас так много параметров ссылок. Почему вы вообще проходите asciiValue? Почему вы передаете StreamReader по ссылке? Что-то, использующее такое множество параметров ref, заставляет меня очень нервничать - почему у вас нет типа, который инкапсулирует все, что вы действительно хотите вернуть из метода?

Вы можете прочитать мою статью о передаче параметров , чтобы лучше понять ref.

...