为什么C#RegexOptions.Compiled会使匹配变慢?

时间:2016-12-03 23:16:12

标签: c# .net regex performance

我有以下代码:

static void Main(string[] args)
{
    const string RegXPattern = @"/api/(?<controller>\w+)/(?<action>\w+)/?$";
    var regex = new Regex(RegXPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);

    const string InputToMatch = "/api/person/load";

    regex.IsMatch(InputToMatch); // Warmup

    var sw = Stopwatch.StartNew();
    for (int i = 0; i < 10000000; i++)
    {
        var match = regex.IsMatch(InputToMatch);
    }
    sw.Stop();

    Console.WriteLine(sw.Elapsed.ToString());
    Console.ReadLine();
}

Releae 下的我的计算机上运行上述内容,在 18 秒内完成并移除RegexOptions.Compiled使其在 13 中运行>秒。

我的理解是,包含此标志会使匹配更快,但在我的示例中,它会导致 ~30%性能降低。

我在这里缺少什么?

2 个答案:

答案 0 :(得分:3)

问题在于已编译的Regex版本与当前表格的区域性进行逐字符比较

if .... char.ToLower(runtext[index2], CultureInfo.CurrentCulture) == 'c' ....

在每个字符中检索静态静态CultureInfo.CurrentCulture线程。

这在分析器中显示为CPU使用者:

enter image description here

我有filed an issue for .NET Corefixed it with a PR。 如果您需要将其合并回常规.NET Framework,则应在github上提交问题以请求反向移植。 对于已设置

的所有已编译正则表达式都会显示该问题
  • RegexOptions.IgnoreCase | RegexOptions.Compiled
  • RegexOptions.CultureInvariant | RegexOptions.Compiled
  • RegexOptions.CultureInvariant | RegexOptions.IgnoreCase RegexOptions.Compiled

看似奇怪的选项 RegexOptions.CultureInvariant |如果您在具有特定语言环境的线程上创建正则表达式,则该表达式实际上是必需的,RegexOptions.Compiled 是必需的,该语言环境带有特殊的大小写或数字分隔符。正则表达式匹配表达式将根据您当前的语言环境专门创建。如果要使用与区域设置无关的Regex,则需要使用RegexOptions.CultureInvariant。

答案 1 :(得分:0)

根据MSDN最佳做法,

  

我们建议您使用特定正则表达式相对不频繁地调用正则表达式方法时使用解释的正则表达式。当您使用特定正则表达式相对频繁地调用正则表达式方法时,应使用已编译的正则表达式。解释的正则表达式的较慢执行速度超过其减少的启动时间所获得的确切阈值,或者编译正则表达式的较慢启动时间超过其较快执行速度的增益的阈值很难确定。它取决于多种因素,包括正则表达式的复杂性和它处理的特定数据。要确定解释或编译的正则表达式是否为您的特定应用程序场景提供最佳性能,您可以使用Stopwatch类来比较它们的执行时间。

此外,您有两个选项提供给正则表达式IgnoreCaseCompiled。如果您删除IgnoreCase,则Compiled选项会为您提供更好的效果。在全局声明Compiled表达式时,通常首选Regex选项,以便在启动时编译它们。