【问题标题】:Why Regex CompileToAssembly giving slower performance than compiled regex and Interpreted Regex?为什么 Regex CompileToAssembly 的性能比已编译的 regex 和 Interpreted Regex 慢?
【发布时间】:2012-04-09 20:16:05
【问题描述】:

我正在使用以下代码针对已编译的正则表达式测试 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

【问题讨论】:

  • 我自己运行了代码。这是我的结果:RegexOptions.Compiled: 8399ms; CompiledToAssembly: 7806ms; Interpreted: 10405ms。正是我所期望的。
  • 在调试模式下在 Visual Studio 中再次尝试,得到大致相同的结果。您分别调用CompileToAssembly(),然后在注释掉该部分的情况下运行,对吗?
  • 我尝试运行 exe 现在结果更好了...不知道为什么我之前尝试它时会给出奇怪的结果。 Neway 的结果仍然与理论不匹配以下是 10000000 次迭代的结果: RegexOption.Compiled: 34413msCompiledToAssembly: 37125 Interpreted: 47322 .... 为什么遵守汇编比编译正则表达式花费更多时间??
  • 我希望你在没有CompileToAssembly(); 的情况下运行这个程序,否则程序集将被重新创建,并且一旦你调用DuplicatedString 就必须再次jitted。从 Best Practices 我们了解到,程序集不是动态加载,而是与您的项目静态链接,即通过在预构建步骤中构建它,这一点很重要。

标签: c# .net regex


【解决方案1】:

您的代码有一个问题:静态字段初始化程序将在运行静态方法之前运行。这意味着在Main() 运行之前已经分配了level4。这意味着level4 引用的对象不是CompileToAssembly() 中创建的类的实例。

请注意,Regex.CompileToAssembly 的示例代码显示了正则表达式的编译及其在两个不同程序中的使用情况。因此,您作为“CompiledToAssembly”计时的实际正则表达式可能是不同的正则表达式您在之前的测试中编译的。

另一个需要考虑的因素:将程序集加载到内存并将其 jit 到机器代码的开销可能非常大,以至于您需要超过 1,000,000 次迭代才能看到好处。

【讨论】:

  • 相差55s!这不是由于一次性加载开销。看我的回答。
  • @usr,当然,这就是为什么我提到它是“另一个需要考虑的因素”。更重要的因素是 OP 的示例代码没有为预期的正则表达式计时。
  • 已经检查了将程序集加载到内存中的时间,与使用 compileToAssembly 选项时每次匹配所花费的时间相比,它可以忽略不计。另外,尝试在 main() 中创建对象没有效果。
  • @user1322631 你检查过match = level4.Match(str) 产生了预期的结果吗?
  • 是的,正则表达式是相同的并给出相同的结果。
【解决方案2】:

您正在调试器 (Visual Studio) 下运行。它将防止在加载程序集时发生 JIT 优化。尝试不使用调试器运行 (ctrl-f5)。

【讨论】:

  • 在没有调试器的情况下不运行不会神奇地将level4 字符串对象转换为已编译的正则表达式。
  • 正则表达式的汇编编译已经完成。这里展示了我是如何将它编译成汇编的。这不是实际的代码。
  • 我尝试运行 exe 现在结果更好了...不知道为什么当我之前尝试它时它会给出奇怪的结果。 Neway 的结果仍然与理论不匹配以下是 10000000 次迭代的结果: RegexOption.Compiled: 34413ms CompiledToAssembly: 37125 Interpreted: 47322 .... 为什么遵守汇编比编译正则表达式花费更多时间??
猜你喜欢
  • 2011-08-25
  • 1970-01-01
  • 2020-02-23
  • 2012-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-02
  • 1970-01-01
相关资源
最近更新 更多