7

Вопрос по .net, regex, c# – Почему Regex CompileToAssembly дает более медленную производительность, чем скомпилированные регулярные выражения и интерпретированные регулярные выражения?

Я использую следующий код для проверки производительности CompileToAssembly против скомпилированного регулярного выражения, но результаты не соответствуют. Пожалуйста, дайте мне знать, что мне не хватает. Спасибо!!!

static readonly Regex regex = new Regex(@"(stats|pause\s?(all|\d+(\,\d+)*)|start\s?(all|\d+(\,\d+)*)|add\s?time\s?(all|\d+(\,\d+)*)(\s\d+)|c(?:hange)?\s?p(?:asskey)?|close)(.*)", RegexOptions.Compiled);
static readonly Regex reg = new Regex(@"(stats|pause\s?(all|\d+(\,\d+)*)|start\s?(all|\d+(\,\d+)*)|add\s?time\s?(all|\d+(\,\d+)*)(\s\d+)|c(?:hange)?\s?p(?:asskey)?|close)(.*)");
static readonly Regex level4 = new DuplicatedString();

    static void Main()
    {
        const string str = "add time 243,3453,43543,543,534534,54534543,345345,4354354235,345435,34543534 6873brekgnfkjerkgiengklewrij";
        const int itr = 1000000;
        CompileToAssembly();
        Match match;
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < itr; i++)
        {
             match = regex.Match(str);
        }
        sw.Stop();
        Console.WriteLine("RegexOptions.Compiled: {0}ms", sw.ElapsedMilliseconds);

        sw.Reset();
        sw.Start();
        for (int i = 0; i < itr; i++)
        {
            match = level4.Match(str);
        }
        sw.Stop();

        Console.WriteLine("CompiledToAssembly: {0}ms", sw.ElapsedMilliseconds);

        sw.Reset();
        sw.Start();
        for (int i = 0; i < itr; i++)
        {
            match = reg.Match(str);
        }
        sw.Stop();
        Console.WriteLine("Interpreted: {0}ms", sw.ElapsedMilliseconds);
        Console.ReadLine();
    }

    public static void CompileToAssembly()
    {
        RegexCompilationInfo expr;
        List<RegexCompilationInfo> compilationList = new List<RegexCompilationInfo>();

        // Define regular expression to detect duplicate words
        expr = new RegexCompilationInfo(@"(stats|pause\s?(all|\d+(\,\d+)*)|start\s?(all|\d+(\,\d+)*)|add\s?time\s?(all|\d+(\,\d+)*)(\s\d+)|c(?:hange)?\s?p(?:asskey)?|close)(.*)",
                   RegexOptions.Compiled,
                   "DuplicatedString",
                   "Utilities.RegularExpressions",
                   true);
        // Add info object to list of objects
        compilationList.Add(expr);

        // Apply AssemblyTitle attribute to the new assembly
        //
        // Define the parameter(s) of the AssemblyTitle attribute's constructor 
        Type[] parameters = { typeof(string) };
        // Define the assembly's title
        object[] paramValues = { "General-purpose library of compiled regular expressions" };
        // Get the ConstructorInfo object representing the attribute's constructor
        ConstructorInfo ctor = typeof(System.Reflection.AssemblyTitleAttribute).GetConstructor(parameters);
        // Create the CustomAttributeBuilder object array
        CustomAttributeBuilder[] attBuilder = { new CustomAttributeBuilder(ctor, paramValues) };

        // Generate assembly with compiled regular expressions
        RegexCompilationInfo[] compilationArray = new RegexCompilationInfo[compilationList.Count];
        AssemblyName assemName = new AssemblyName("RegexLib, Version=1.0.0.1001, Culture=neutral, PublicKeyToken=null");
        compilationList.CopyTo(compilationArray);
        Regex.CompileToAssembly(compilationArray, assemName, attBuilder);
    }

Ниже приведены результаты:

RegexOptions.Compiled: 3908ms
CompiledToAssembly: 59349ms
Interpreted: 5653ms

Я надеюсь, что вы запустили это без линии<code>CompileToAssembly();</code>в противном случае сборка будет воссоздана и должна быть снова подключена после вызова<code>DuplicatedString</code>, От<a href="https://msdn.microsoft.com/en-us/library/gg578045%28v=vs.110%29.aspx#Interpreted" rel="nofollow noreferrer">Best Practices</a> мы узнаем, что важно, чтобы сборка<i>not</i> динамически загружается, но статически связан с вашим проектом, т. е. собирается на этапе предварительной сборки.

Apr 18, 2015, 12:23 AMот

Я просто запустил код сам. Вот мои результаты:<code>RegexOptions.Compiled: 8399ms</code>; <code>CompiledToAssembly: 7806ms</code>; <code>Interpreted: 10405ms</code>, Как раз то, что я ожидал.

Apr 09, 2012, 10:03 PMот

Попробовал еще раз в Visual Studio в режиме отладки, получил примерно те же результаты. Ты звонишь<code>CompileToAssembly()</code> отдельно, затем работает с этой частью закомментировано, правильно?

Apr 09, 2012, 10:12 PMот

Я попытался запустить exe, теперь результаты лучше ... Не знаю, почему он давал странные результаты, когда я пытался сделать это раньше. Тем не менее, результаты не совпадают с теорией. Ниже приведены результаты для 10000000 итераций: RegexOption.Compiled: 34413msCompiledToAssembly: 37125 Интерпретировано: 47322 .... Почему соответствие сборке заняло больше времени, чем скомпилированное регулярное выражение ??

Apr 09, 2012, 10:17 PMот

2ответа

4

Вы работаете под отладчиком (Visual Studio). Это предотвратит JIT-оптимизацию при загрузке сборки. Попробуйте запустить без отладчика (Ctrl-F5).

6

У вашего кода есть проблема: будут запускаться инициализаторы статического поляbefore статические методы запускаются. Это означает, чтоlevel4 уже был назначен ранееMain() пробеги. Это означает, что объект, на который ссылаетсяlevel4 являетсяnot экземпляр класса, созданный вCompileToAssembly().

Обратите внимание, что пример кода дляRegex.CompileToAssembly показывает компиляцию регулярного выражения и его потребление вtwo different programs.  Фактическое регулярное выражение, которое вы указали как «CompiledToAssembly» следовательно, это может быть другое регулярное выражение, которое вы скомпилировали в предыдущем тесте.

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

RelatedQuestions