Алгоритм ускорения синтаксического анализа - PullRequest
4 голосов
/ 10 марта 2011

Я пытаюсь разобрать некоторые файлы ddump, не могли бы вы помочь мне ускорить мой алгоритм?
Это занимает 216 мс для каждого цикла !! это слишком много. Я хотел бы иметь около 40-50 мс на цикл. Может быть, с помощью RegExp?

Вот мой алгоритм:

 while (pos < EntireFile.Length && (/*curr = */EntireFile.Substring(pos, EntireFile.Length - pos)).Contains(" class"))
            {
                w.Reset();
                w.Start();
                pos = EntireFile.ToLower().IndexOf(" class", pos) + 6;
                int end11 = EntireFile.ToLower().IndexOf("extends", pos);
                if (end11 == -1)
                    end11 = EntireFile.IndexOf("\r\n", pos);
                else
                {
                    int end22 = EntireFile.IndexOf("\r\n", pos);
                    if (end22 < end11)
                        end11 = end22;
                }
                //string opcods = EntireFile.Substring(pos, EntireFile.Length - pos);
                string Cname = EntireFile.Substring(pos, end11 - pos).Trim();
                pos += (end11 - pos) + 7;
                pos = EntireFile.IndexOf("{", pos) +1;</p>

<code>            int count = 1;
            string searching = EntireFile.Substring(pos, EntireFile.Length - pos);
            int searched = 0;
            while (count != 0)
            {
                if (searching[searched] == '{')
                    count++;
                else if (searching[searched] == '}')
                    count--;

                searched++;
            }
            string Content = EntireFile.Substring(pos, searched);
            tlist.Add(new TClass() { ClassName = Cname, Content = Content });
            pos += searched;

            if (pos % 3 == 0)
            {
                double prc = ((double)pos) * 100d / ((double)EntireFile.Length);
                int prcc = (int)Math.Round(prc);
                wnd.UpdateStatus(prcc);
                wnd.Update();
            }
            mils.Add((int)w.ElapsedMilliseconds);
        }
</code>

Любая помощь будет принята с благодарностью.

Ответы [ 5 ]

9 голосов
/ 10 марта 2011

Ну, делать это несколько раз

EntireFile.ToLower()

конечно не поможет.Вы можете сделать несколько вещей:

  1. Выполнять дорогостоящие операции (ToLower, IndexOf и т. Д.) Только один раз и кэшировать результаты, если это возможно.
  2. Не сужайтена входе, который вы обрабатываете с помощью SubString, это снизит вашу производительность.Вместо этого сохраните отдельное значение int parseStart и используйте его в качестве дополнительного параметра для всех ваших вызовов IndexOf.Другими словами, следите за частью файла, которую вы проанализировали вручную, вместо того, чтобы каждый раз брать меньшую подстроку.
1 голос
/ 07 апреля 2013

во-первых, вы можете изменить

while (pos < EntireFile.Length && (/*curr = */EntireFile.Substring(pos, EntireFile.Length - pos)).Contains(" class"))
{
 ...
}

на

var loweredEntireFile = EntireFile.ToLower();

while (pos < loweredEntireFile.Length && 
       Regex.IsMatch(loweredEntireFile, " class",   
       RegexOptions.IgnoreCase)
{
...

    // we just need to process the rest of the file
    loweredEntireFile = loweredEntireFile.Substring(pos, loweredEntireFile.Length - pos));
}

, а затем изменить

pos = EntireFile.ToLower().IndexOf(" class", pos) + 6;
int end11 = EntireFile.ToLower().IndexOf("extends", pos);

на

var matches = Regex.Matchs(loweredEntireFile, " class", RegexOptions.IgnoreCase);
pos = matches.First().Index;

matches = Regex.Matchs(loweredEntireFile, "extends", RegexOptions.IgnoreCase);
var end11 = matches.First().Index;

как другоеПредполагается, что

var loweredEntiredFile = EntiredFile.ToLower();

следует выполнить один раз за пределами while, а

loweredEntireFile = loweredEntireFile.Substring(pos, loweredEntireFile.Length - pos));

необходимо выполнить в конце while

1 голос
/ 10 марта 2011

В дополнение к ответу Джона, насколько я понимаю, все в вашей части while () вашего кода будет выполняться в каждом цикле.Так что вам может быть быстрее найти способ не пересчитать его

EntireFile.Substring(pos, EntireFile.Length - pos)).Contains(" class")

на каждой итерации цикла while.Кроме того, что именно вы пытаетесь разобрать?Это обычный текстовый файл?Вы не дали много деталей.Один из методов, который мне нравится использовать для разбора текстовых файлов, - это загрузить весь файл в массив строк, используя '\ n' в качестве разделителя.Затем я могу быстро пройтись по массиву и разобрать содержимое.Если мне нужно, я могу сохранить индекс массива и быстро обратиться к предыдущей строке.

1 голос
/ 10 марта 2011

Я бы порекомендовал использовать инструмент профилирования, чтобы сосредоточиться на части кода, которая замедляет работу.

JetBrains dotTrace - это один продукт для профилирования, который очень помог в решении этой задачи.

1 голос
/ 10 марта 2011

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

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

Кроме того, сравнение без учета регистра не выполняется при понижении или повышении строки!Вы используете класс StringComparer или перечисление StringComparsion.Существует много перегрузок строк, которые позволяют вам указать, следует ли учитывать чувствительность к регистру.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...