Проблема с производительностью REGEX при использовании IsMatch

У меня есть следующее регулярное выражение, которое я использовал для перенаправления

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

Регулярное выражение работает нормально, но когда дело доходит до большого количества запросов, наш процессор загружается на 100%.

Есть ли какое-нибудь решение для оптимизации вышеперечисленного?

Спасибо

Используйте String.Contains("/articles/my-atricle") и полностью пропустите regex.

Ryan Wilson 13.09.2018 19:59

Сколько там matchPattern? Вы можете попробовать скомпилировать их и сохранить в словаре по шаблону. Кроме того, перенос matchPattern.Trim() в отдельную переменную не решит проблему, но все же неплохо.

Guru Stron 13.09.2018 20:01

@GuruStron, что вы имеете в виду, собирая их? Извините за вопрос noob, но я не так хорошо знаком с регулярным выражением

Hishaam Namooya 13.09.2018 20:04

@HishaamNamooya см. это

Guru Stron 13.09.2018 20:06

@HishaamNamooya - Я считаю, что идея заключалась в использовании флага RegexOptions.Compiled, но делайте это только в том случае, если вы собираетесь сохранить этот Regex и повторно использовать его.

pstrjds 13.09.2018 20:07

@HishaamNamooya - Я также только что заметил, что requestedPathAndQuery и requestedRawUrl идентичны. Это намеренно? Если это так, вы можете удалить одно из своих сравнений. Это должно немного повысить производительность.

pstrjds 13.09.2018 20:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
110
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я бы попытался создать реальную переменную 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 и его повторном использовании?

Hishaam Namooya 13.09.2018 20:08

@HishaamNamooya - Да, и, как было указано в других комментариях, вы могли бы пойти еще дальше и использовать флаг Compiled, который даст вам еще лучшую производительность, НО прочитайте связанную статью, в которой объясняется, что он делает. Вы обязательно захотите сохранить этот объект Regex где-нибудь в своем классе или в коллекции. НЕ создавайте Regex с опцией Compiled каждый раз, когда вызывается ваша функция.

pstrjds 13.09.2018 20:10

Выражение будет другим. У меня около 18K разных шаблонов, и каждый раз, когда появляется HTTP-запрос, он вызывает мой метод перенаправления, который содержит приведенный выше код.

Hishaam Namooya 13.09.2018 20:38

@HishaamNamooya - Удалено примечание о повторном использовании выражения. Вы обратили внимание на мой комментарий к основному вопросу об одинаковых строках. Если бы вы удалили одно из них, это спасло бы вас от сравнения.

pstrjds 13.09.2018 21:01

Применение предоставленного вами кода и удаление дополнительного IsMatch, похоже, решает проблему. Я буду следить за ним на всякий случай

Hishaam Namooya 13.09.2018 21:06

Как я уже говорил в комментариях, если вы ожидаете только ограниченное количество различных шаблонов, которые могут быть повторно использованы в течение жизненного цикла вашего приложения, вы можете создать статический Dictionary (я думаю, лучше использовать одновременный one) и кэшировать эти регулярные выражения и повторно использовать их.

РЕДАКТИРОВАТЬ

пример кода:

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 для вас, потому что она действительно может сделать вещи помедленнее

Другие вопросы по теме