Код для разбора текста в файлах замедляется до остановки c # - PullRequest
4 голосов
/ 21 сентября 2011
 private static void BuildDictionaryOfRequires(Regex exp, Dictionary<string, string> dictionary, DirectoryInfo dir)
    {
        var i = 0;
        var total = dir.EnumerateFiles("*.*", SearchOption.AllDirectories).
                                 Where(x => x.Extension == ".aspx" || x.Extension == ".ascx").Count();
        foreach (var item in dir.EnumerateFiles("*.*", SearchOption.AllDirectories).
                                 Where(x => x.Extension == ".aspx" || x.Extension == ".ascx"))
        {
 #if DEBUG
            Stopwatch sw = Stopwatch.StartNew();
 #endif

            var text = File.ReadAllText(item.FullName);

            MatchCollection matches = exp.Matches(text);
            foreach (Match match in matches)
            {
                var matchValue = match.Groups[0].Value;

                if (dictionary.ContainsKey(matchValue))
                {
                    dictionary[matchValue] = string.Format("{0},{1}", dictionary[matchValue], item.Name);
                }
                else
                {
                    dictionary.Add(matchValue, item.Name);
                }
            }

            Console.WriteLine(string.Format("Found matches in {0}.", item.Name));

 #if DEBUG
            sw.Stop();
            Console.WriteLine("Time used (float): {0} ms", sw.Elapsed.TotalMilliseconds);
 #endif


            Console.WriteLine(string.Format("{0} of {1}", (++i).ToString(), total));
        }
    }

Есть около 232 файлов, которые лямбда находит.Он просто разрывается на 160, а потом начинает ползти.Я сейчас профилирую код, но мне интересно, если есть что-то очевидное, я делаю что-то не так.

регулярное выражение

    Regex exp = new Regex(@"dojo\.require\([""'][\w\.]+['""]\);?", RegexOptions.IgnoreCase | RegexOptions.Compiled);

все файлы имеют одинаковую длину и одинаковую структуру.

большинство файлов занимают менее 30 мс, а некоторые - 11251 мс.

с обновленным регулярным выражением весь процесс теперь занимает 1700 мс.уф!

Ответы [ 3 ]

2 голосов
/ 21 сентября 2011

Я думаю, что текущая оскорбительная часть является частью регулярного выражения здесь:

(\w+\.?)*

Удалить? и добавьте \w*, и вы сопоставите все одинаковые строки, но гораздо эффективнее.

(\w+\.?)* может соответствовать asdf разными способами:

  • ASDF
  • ASD, е
  • а, D, F
  • а, с, д, е
  • а, сд, F
  • а, SDF
  • , как, ДФ

Я предполагаю, что некоторые из ваших файлов содержали такие строки:

dojo.require('asdf')  //with no ;

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

Попробуйте использовать:

Regex exp = new Regex(@"dojo\.require\((\""|\')((\w+\.)*\w*)(\""|\')\);");
2 голосов
/ 21 сентября 2011

Попробуйте упростить свое регулярное выражение:

Regex exp = new Regex(@"dojo\.require\([""'][\w\.]+[""']\)", RegexOptions.IgnoreCase | RegexOptions.Compiled);

ОБНОВЛЕНИЕ : Затем удалите точку с запятой в конце, если хотите соответствовать своему примеру.

1 голос
/ 21 сентября 2011

Несколько вещей:

  1. принять вызов DiscardBufferedData.Вам это не нужно, и это дорого.
  2. Исправить двойную утилизацию.Обратите внимание, что Close также вызывает Dispose, так что вы также можете избавиться от этого.
  3. На самом деле, существует метод File.ReadAllText, который можно использовать для избавления от создаваемых и утилизируемых потоковых ридеров.
...