首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >何时不使用RegexOptions.Compiled

何时不使用RegexOptions.Compiled
EN

Stack Overflow用户
提问于 2012-04-01 23:10:04
回答 4查看 36.6K关注 0票数 71

我理解使用RegexOptions.Compiled的好处--它通过使用编译形式的正则表达式而不是在运行时解释它,从而提高了应用程序的执行时间。虽然不建议应用程序使用这种方法,但在启动时已经很慢了。

但如果我的申请能承受启动时间的任何增加-

我不应该使用RegexOptions.Compiled的其他场景是什么?

作为一个注解,我把这个方法叫了好几次-

代码语言:javascript
复制
private static string GetName(string objString)
{
    return Regex.Replace(objString, "[^a-zA-Z&-]+", "");
}

因此,对“objString”使用不同的值调用此方法(尽管objString的值也可能重复)。

你认为在这里使用RegexOptions.Compiled好/不好吗?任何网络链接都会很有帮助。

谢谢!

编辑

我用两个都测试了我的web应用程序

  • RegexOptions.Compiled,和
  • Regex实例化为类变量

但是我发现我的web应用程序所花费的时间并没有很大的不同--在这两种情况下,我注意到的是,当应用程序第一次加载时,它所花费的时间是连续加载页面所需时间的两倍,这与我是否使用RegexOptions.Compiled无关。

任何评论--

为什么我的web应用程序第一次处理Regex所花费的时间更长,在随后的负载中所花费的时间几乎减少了一半--这里是否有任何内置缓存或其他.net功能在帮助您。不管我是否使用RegexOptions.Compiled,这个东西都是一样的。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-04-01 23:29:46

对于任何像这样的具体性能问题,最好的方法是测试和查看哪种方式更快。

一般来说,编译regex不太可能有多大的好处,除非您经常使用regex,或者是在非常大的字符串上。(或者两者都是)我认为,在您确定存在性能问题并认为这可能会有所帮助之后,尝试更多的是优化,而不是随机尝试。

有关RegexOptions.Compiled缺点的一些一般性讨论,请参阅杰夫·阿特伍德的这篇博文;它非常古老(从.NET Framework1.1时代起),但据我所知,自编写以来,主要的相关事实都没有改变。

票数 46
EN

Stack Overflow用户

发布于 2012-04-01 23:53:53

需要考虑的两件事是,RegexOptions.Compiled占用了CPU时间和内存。

考虑到这一点,基本上只有一个实例应该是而不是使用RegexOptions.Compiled:

  • 您的正则表达式只运行几次,运行时的网络加速不能证明编译的成本是合理的。

可以说,在沙中有太多的变量来预测和画一条线。确定最佳方法确实需要测试。或者,如果您不想进行测试,那么在不使用Compiled之前不要使用它。

现在,如果您确实选择了RegexOptions.Compiled,那么重要的是不要浪费它。

通常,最好的方法是将对象定义为可以反复使用的静态变量。例如..。

代码语言:javascript
复制
public static Regex NameRegex = new Regex(@"[^a-zA-Z&-]+", RegexOptions.Compiled);

这种方法的一个问题是,如果您在全局声明它,那么如果您的应用程序不总是使用它,或者在启动时不使用它,那么它可能是一种浪费。因此,一种稍微不同的方法是使用懒惰加载,正如我在昨天写的文章中描述的那样。

在这种情况下会是这样的..。

代码语言:javascript
复制
public static Lazy<Regex> NameRegex = 
    new Lazy<Regex>(() => new Regex("[^a-zA-Z&-]+", RegexOptions.Compiled));

然后,只要您想要使用这个正则表达式,只需在第一次访问它时实例化它,就直接引用NameRegex.Value

现实世界中的RegexOptions.Compiled

在我的几个站点上,我使用了ASP.NET MVC的Regex路由。这个场景是对RegexOptions.Compiled的完美使用。这些路由是在web应用程序启动时定义的,然后只要应用程序继续运行,这些路由就会被用于所有后续请求。因此,这些正则表达式被实例化和编译一次,并重复使用数百万次。

票数 40
EN

Stack Overflow用户

发布于 2012-04-02 03:59:21

BCL博客文章中,编译使启动时间增加了一个数量级,但随后的运行时却减少了大约30%。使用这些数字,应该考虑对模式进行编译,您需要对其进行30次以上的评估。(当然,与任何性能优化一样,这两种备选方案都应衡量其可接受性。)

如果性能对于重复调用的简单表达式至关重要,则可能希望完全避免使用正则表达式。我试着运行一些变体,每次运行大约500万次:

注:编辑自上一版本,以纠正正则表达式。

代码语言:javascript
复制
    static string GetName1(string objString)
    {
        return Regex.Replace(objString, "[^a-zA-Z&-]+", "");
    }

    static string GetName2(string objString)
    {
        return Regex.Replace(objString, "[^a-zA-Z&-]+", "", RegexOptions.Compiled);
    }

    static string GetName3(string objString)
    {
        var sb = new StringBuilder(objString.Length);
        foreach (char c in objString)
            if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '&')
                sb.Append(c);
        return sb.ToString();
    }


    static string GetName4(string objString)
    {
        char[] c = objString.ToCharArray();
        int pos = 0;
        int writ = 0;
        while (pos < c.Length)
        {
            char curr = c[pos];
            if ((curr >= 'A' && curr <= 'Z') || (curr >= 'a' && curr <= 'z') || curr == '-' || curr == '&')
            {
                c[writ++] = c[pos];
            }
            pos++;
        }
        return new string(c, 0, writ);
    }


    unsafe static string GetName5(string objString)
    {
        char* buf = stackalloc char[objString.Length];
        int writ = 0;
        fixed (char* sp = objString)
        {
            char* pos = sp;
            while (*pos != '\0')
            {
                char curr = *pos;
                if ((curr >= 'A' && curr <= 'Z') ||
                    (curr >= 'a' && curr <= 'z') ||
                     curr == '-' || curr == '&')
                    buf[writ++] = curr;
                pos++;
            }
        }
        return new string(buf, 0, writ);
    }

独立执行500万个随机的ASCII字符串,每个字符串30个字符,一致地给出以下数字:

代码语言:javascript
复制
   Method 1: 32.3  seconds (interpreted regex)
   Method 2: 24.4  seconds (compiled regex)
   Method 3:  1.82 seconds (StringBuilder concatenation)
   Method 4:  1.64 seconds (char[] manipulation)
   Method 5:  1.54 seconds (unsafe char* manipulation)

也就是说,编译为这种模式的大量评估提供了大约25%的性能效益,第一次执行速度大约慢了3倍。对底层字符数组进行操作的方法比编译的正则表达式快12倍。

方法4或方法5可能比正则表达式提供一些性能好处,而其他方法可能提供其他好处(可维护性、可读性、灵活性等)。这个简单的测试确实表明,在这种情况下,编译regex比对大量评估解释regex有一定的性能好处。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9969158

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档