【问题标题】:REGEX Performance Issue when using IsMatch使用 IsMatch 时的 REGEX 性能问题
【发布时间】:2018-09-14 03:09:25
【问题描述】:

我有以下用于执行重定向的正则表达式

string requestedPath = HttpUtility.UrlDecode(this.StripLanguage(currentContext.InputUrl.AbsolutePath));
string requestedPathAndQuery = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);
string requestedRawUrl = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);
string requestedUrl =
    HttpUtility.UrlDecode(
        string.Concat(
            currentContext.InputUrl.Scheme,
            "://",
            currentContext.InputUrl.Host,
            requestedRawUrl));

string requestedRawUrlDomainAppended = HttpUtility.UrlDecode(currentContext.InputUrl.AbsoluteUri);
string requestedPathWithCulture = HttpUtility.UrlDecode(currentContext.InputUrl.AbsolutePath);

                    var finalRequestedURL = string.Empty;
finalRequestedURL = Regex.IsMatch(requestedPathAndQuery,matchPattern.Trim(),RegexOptions.IgnoreCase)
                    ? requestedPathAndQuery
                    : Regex.IsMatch(requestedPath,matchPattern.Trim(),RegexOptions.IgnoreCase)
                        ? requestedPath
                        : Regex.IsMatch(requestedPathWithCulture,matchPattern.Trim(),RegexOptions.IgnoreCase)
                            ? requestedPathWithCulture
                            : Regex.IsMatch(requestedRawUrl,matchPattern.Trim(),RegexOptions.IgnoreCase)
                                ? requestedRawUrl
                                : Regex.IsMatch(requestedUrl,matchPattern.Trim(),RegexOptions.IgnoreCase)
                                    ? requestedRawUrlDomainAppended
                                    : string.Empty;

matchPattern 变量是 URL。示例:(.*)/articles/my-article(.*) 应该重定向到 http://www.google.com

正则表达式工作正常,但是当涉及到大量请求时,我们的 CPU 会达到 100%。

有什么办法可以优化上面的吗?

谢谢

【问题讨论】:

  • 使用 String.Contains("/articles/my-atricle") 并完全跳过 regex
  • 有多少个matchPattern?您可以尝试编译它们并根据模式存储在字典中。将matchPattern.Trim() 移动到单独的变量也不能解决问题,但仍然很好。
  • @GuruStron 编译它们是什么意思?对不起菜鸟问题,但我对正则表达式不太熟悉
  • @HishaamNamooya 见this
  • @HishaamNamooya - 我相信这个想法是使用 RegexOptions.Compiled 标志,但只有当你要存储 Regex 并重复使用它时才这样做。

标签: c#


【解决方案1】:

我会尝试创建一个实际的Regex 变量并重用它。这应该有助于加快速度。我也可能会建议将三元业务更改为常规的 if/else if/else 语句。我认为它会更具可读性(只是个人意见)。

string requestedPath = HttpUtility.UrlDecode(this.StripLanguage(currentContext.InputUrl.AbsolutePath));
string requestedPathAndQuery = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);
string requestedRawUrl = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);
string requestedUrl =
    HttpUtility.UrlDecode(
        string.Concat(
            currentContext.InputUrl.Scheme,
            "://",
            currentContext.InputUrl.Host,
            requestedRawUrl));

string requestedRawUrlDomainAppended = HttpUtility.UrlDecode(currentContext.InputUrl.AbsoluteUri);
string requestedPathWithCulture = HttpUtility.UrlDecode(currentContext.InputUrl.AbsolutePath);

var regex = new Regex(matchPattern.Trim(), RegexOptions.IgnoreCase);
var finalRequestedURL = regex.IsMatch(requestedPathAndQuery)
                    ? requestedPathAndQuery
                    : regex.IsMatch(requestedPath)
                        ? requestedPath
                        : regex.IsMatch(requestedPathWithCulture)
                            ? requestedPathWithCulture
                            : regex.IsMatch(requestedRawUrl)
                                ? requestedRawUrl
                                : regex.IsMatch(requestedUrl)
                                    ? requestedRawUrlDomainAppended
                                    : string.Empty;

编辑

正如我在上面的评论中指出的那样,有两个相同的字符串,如果您删除其中一个,可以节省比较时间。

string requestedPath = HttpUtility.UrlDecode(this.StripLanguage(currentContext.InputUrl.AbsolutePath));
string requestedPathAndQuery = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);

// This string is identical to requestPathAndQuery, so I am removing it
// string requestedRawUrl = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);

string requestedUrl =
    HttpUtility.UrlDecode(
        string.Concat(
            currentContext.InputUrl.Scheme,
            "://",
            currentContext.InputUrl.Host,
            requestedRawUrl));

string requestedRawUrlDomainAppended = HttpUtility.UrlDecode(currentContext.InputUrl.AbsoluteUri);
string requestedPathWithCulture = HttpUtility.UrlDecode(currentContext.InputUrl.AbsolutePath);

var regex = new Regex(matchPattern.Trim(), RegexOptions.IgnoreCase);
var finalRequestedURL = string.Empty;

// You could even add in brackets here to aid readability but this
// helps remove the indententation/nesting that makes the code harder
// to read and follow
if (regex.IsMatch(requestedPathAndQuery)) finalRequestURL = requestedPathAndQuery;
else if(regex.IsMatch(requestedPath)) finalRequestURL = requestedPath;
else if (regex.IsMatch(requestedPathWithCulture)) finalRequestURL = requestedPathWithCulture;
else if (regex.IsMatch(requestedUrl)) finalRequestURL = requestedRawUrlDomainAppended;

【讨论】:

  • 那么,主要的变化是初始化Regex然后重用它?
  • @HishaamNamooya - 是的,正如在其他 cmets 中指出的那样,您可以更进一步并使用 Compiled 标志,这将为您提供更好的性能,但请阅读链接文章解释了它的作用。您绝对希望将该 Regex 对象存储在您的类中的某个地方或集合中。不要在每次调用函数时使用 Compiled 选项创建 Regex。
  • 表达方式会有所不同。我有大约 18K 的不同模式,每次有 http 请求时,它都会调用包含上述代码的重定向方法
  • @HishaamNamooya - 删除了关于重用表达式的注释。您是否注意到我对有关相同字符串的主要问题的评论。如果您删除其中一个,它将为您节省比较。
  • 应用您提供的代码并删除额外的 IsMatch 似乎可以解决问题。我会监控它以防万一
【解决方案2】:

正如我在 cmets 中所说,如果您预计只有有限数量的不同模式可以在您的应用程序的生命周期中重复使用,您可以创建一个静态 Dictionary(我认为最好使用 concurrent 一个)并缓存这个正则表达式和重复使用它们。

编辑

示例代码:

public class MyHandler
{
    private static ConcurrentDictionary<string, Regex> dict = new ConcurrentDictionary<string, Regex>();

    public void Handle(string urlPattern)
    {
        urlPattern = urlPattern.Trim();
        var regex = dict.GetOrAdd(urlPattern, s => new Regex(urlPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase));
        // use regex
    }
}

还要测试RegexOptions.Compiled 选项是否适合你,因为它实际上可以使事情slower

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    相关资源
    最近更新 更多