У меня есть следующее регулярное выражение, которое я использовал для перенаправления
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%.
Есть ли какое-нибудь решение для оптимизации вышеперечисленного?
Спасибо
Сколько там matchPattern
? Вы можете попробовать скомпилировать их и сохранить в словаре по шаблону. Кроме того, перенос matchPattern.Trim()
в отдельную переменную не решит проблему, но все же неплохо.
@GuruStron, что вы имеете в виду, собирая их? Извините за вопрос noob, но я не так хорошо знаком с регулярным выражением
@HishaamNamooya см. это
@HishaamNamooya - Я считаю, что идея заключалась в использовании флага RegexOptions.Compiled, но делайте это только в том случае, если вы собираетесь сохранить этот Regex
и повторно использовать его.
@HishaamNamooya - Я также только что заметил, что requestedPathAndQuery
и requestedRawUrl
идентичны. Это намеренно? Если это так, вы можете удалить одно из своих сравнений. Это должно немного повысить производительность.
Я бы попытался создать реальную переменную 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 - Да, и, как было указано в других комментариях, вы могли бы пойти еще дальше и использовать флаг Compiled
, который даст вам еще лучшую производительность, НО прочитайте связанную статью, в которой объясняется, что он делает. Вы обязательно захотите сохранить этот объект Regex где-нибудь в своем классе или в коллекции. НЕ создавайте Regex с опцией Compiled каждый раз, когда вызывается ваша функция.
Выражение будет другим. У меня около 18K разных шаблонов, и каждый раз, когда появляется HTTP-запрос, он вызывает мой метод перенаправления, который содержит приведенный выше код.
@HishaamNamooya - Удалено примечание о повторном использовании выражения. Вы обратили внимание на мой комментарий к основному вопросу об одинаковых строках. Если бы вы удалили одно из них, это спасло бы вас от сравнения.
Применение предоставленного вами кода и удаление дополнительного IsMatch, похоже, решает проблему. Я буду следить за ним на всякий случай
Как я уже говорил в комментариях, если вы ожидаете только ограниченное количество различных шаблонов, которые могут быть повторно использованы в течение жизненного цикла вашего приложения, вы можете создать статический 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
для вас, потому что она действительно может сделать вещи помедленнее
Используйте
String.Contains("/articles/my-atricle")
и полностью пропуститеregex
.