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

Если вы можете разделить метод регулярного выражения и использовать тест для проверки сравнения, вы можете ускорить регулярное выражение, если вам действительно нужно.

Перевод книги « Как ускорить регулярные выражения под давлением производства» , автор Дэвид Истман.

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

Во многих случаях применения скорость регулярных выражений не является проблемой. Он просто фиксирует некоторые вопросы через форму. Но когда скорость имеет значение, вы внезапно становитесь детективом, ищущим убийцу времени. Это заставляет вас выяснять, какие фрагменты кода неэффективны, но необходимость ускорения в условиях производственного давления — непростая задача.

Я буду использовать пример C#, но суть в том, что обычно вам нужно обращать внимание на то, как использовать регулярные выражения на любом языке, который вы используете, и такие варианты, как компиляция регулярных выражений, могут помочь.

Когда я сравниваю скорость выполнения, мне приходится использовать какой-то эталонный инструмент, чтобы провести корректное сравнение. К счастью, BenchmarkDotNet уже существует. Он работает для консольных приложений, что нам и нужно.

Я буду продолжать использовать код Visual Studio, поскольку он лучше подходит для создания и отображения проектов без необходимости решения. Чтобы ускорить процесс, я буду использовать шаблоны.

Открыв Warp , я сначала выполнил следующие шаги:

Это просто создает проект, названный в нашу честь, используя доступный эталонный шаблонBenchmarkRegex для настройки соответствующей структуры проекта. Мы можем увидеть сгенерированные файлы, расположенные в каталоге:

Затем мы можем code .запустить VS Code с помощью этой команды.

Но сначала давайте рассмотрим некоторые задачи, связанные с регулярными выражениями, которые я решал в своей предыдущей статье. Мы использовали хитрый шаблон , который использует чередование и обход, чтобы продемонстрировать, что «i до e, кроме после c» часто нарушается в английском языке:

Приведенный выше шаблон находит деструктивные примеры, ища «cie» или «ei» без «c». Обратите внимание, что просмотр — это одна из функций регулярных выражений, которая может вести себя по-разному в разных реализациях, и ее следует использовать с осторожностью. В этом случае мы используем отрицательный просмотр вперед (?<!c), чтобы подтвердить, что «ei» не предшествует «c», но не использует этот «c». Прочтите статью для более подробной информации.

Мы можем поместить этот пример текста и шаблона непосредственно в наш новый файл шаблона _Benchmark.cs_:

using System; 
using System.Text.RegularExpressions; 
using BenchmarkDotNet; 
using BenchmarkDotNet.Attributes; 
namespace BenchmarkRegex 
{ 
   public class Benchmarks 
   { 
      private const string Pattern = @"(cie|(?<!c)ei)"; 
      private const string GoodText = "Good: ceiling, receipt, deceive, chief, field, believe."; 
      private const string BadText = "Bad: species, science, sufficient, seize, vein, weird."; 
      static bool printMeOnce = false; 
 
     [Benchmark] 
      public void Scenario1() 
      { 
         // Implement your benchmark here var 
         f = Regex.IsMatch(GoodText + BadText, Pattern); 
         if (!printMeOnce) foreach (Match match in Regex.Matches(GoodText+BadText, Pattern, RegexOptions.None)) 
            Console.WriteLine("Found '{0}' at position {1}", match.Value, match.Index); 
         printMeOnce = true; 
      } 
   } 
}

Сначала мы проверяем, действительно ли совпадение и охватывает ли оно шесть случаев.

Мы можем протестировать консольное приложение только в режиме выпуска, и это нормально, поэтому мы можем запустить его из командной строки Warp dotnet run -C Release. Вскоре в логах мы получили подтверждение о том, что зафиксировано шесть случаев:

Наконец, мы получаем эталон:

Хорошо, отлично. Конечно, теперь нам нужно вернуться к нашей теме — ускорению регулярных выражений. Итак, первый и достаточно очевидный подход — сделать схему статической . Теперь, когда мы убедились, что шаблон работает, мы можем отказаться от распечатки, ведь это очень замедляет тест!

.. 
private const string Pattern = @"(cie|(?<!c)ei)"; 
private static readonly string StaticPattern = @"(cie|(?<!c)ei)"; 
.. 
[Benchmark] public void Scenario1() 
{ 
  // Implement your benchmark here 
  Regex.Matches(GoodText+BadText, Pattern, RegexOptions.None); 
} 
 
[Benchmark] public void Scenario2() 
{ 
  // Implement your benchmark here 
  Regex.Matches(GoodText+BadText, StaticPattern, RegexOptions.None); 
} 
..

Поэтому мы примерно ожидаем, что второй сценарий будет быстрее. Это действительно так:

(Да, без печати мы находимся в наносекундном диапазоне.)

Теперь, когда у нас есть тестовые тесты, мы можем проверить параметры компиляции:

private const string Pattern = @"(cie|(?<!c)ei)"; 
private static readonly string StaticPattern = @"(cie|(?<!c)ei)"; 
private static readonly Regex CompiledRegex = new(Pattern, RegexOptions.Compiled); 
.. 
[Benchmark] public void Scenario3() 
{ 
   CompiledRegex.Matches(GoodText+BadText); 
} 
..

Итак, как складывается этот тест?

Ну, примерно половина. Но это не однозначный вывод. Внутри и вокруг него происходит много всего, о чем вам нужно знать.

Когда вы впервые начали использовать C#, вы, возможно, помните, что узнали, что он был переведен на промежуточный язык (IL или MSIL), а затем скомпилирован в собственный формат операционной системы посредством JIT-компиляции. (Это казалось несколько неактуальным, когда в 2000 году был выпущен C#, поскольку Microsoft была тесно связана с Windows.)

Однако Regex генерирует свои собственные узлы, деревья синтаксического анализа и операции, а затем преобразует их в IL. Имейте в виду, что Regex — более старая технология, чем .NET — примерно на полвека. Это отчасти объясняет, почему при обращении с ним существуют особые правила.

Без флага Compile созданный объект Regex интерпретируется как указанный выше набор внутренних операций. Эти коды операций преобразуются в IL, чтобы JIT-компилятор мог выполнять их при вызове методов объекта (например, _Match_). Это нормально, если вы делаете несколько вызовов Regex. Если определение Regex является статическим , код операции кэшируется . По умолчанию кэшируются 15 последних использованных кодов действий. Если вы используете много схем, вы можете использовать свойство Regex.CacheSize, чтобы изменить этот параметр.

Если используется флаг Compile, предварительно скомпилированные регулярные выражения увеличивают время запуска, но выполнение отдельных методов сопоставления с образцом происходит быстрее. Это полезно, если вы неоднократно используете определенные шаблоны.

Вы можете создать объект и схему Regex, скомпилировать их и сохранить в отдельной сборке . Вы можете вызвать метод Regex.CompileToAssembly, чтобы скомпилировать и сохранить его. Однако имеет смысл учитывать это при проектировании, поскольку вы разбиваете приложение на отдельные сборки.

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

Эта статья была впервые опубликована на Yunyunzhongsheng ( https://yylives.cc/ ), приглашаем всех посетить ее.

Я решил отказаться от открытого исходного кода Hongmeng Ван Чэнлу, отец Hongmeng с открытым исходным кодом: Hongmeng с открытым исходным кодом — единственное мероприятие в области промышленного программного обеспечения, посвященное архитектурным инновациям в области базового программного обеспечения в Китае: выпущен OGG 1.0, Huawei предоставляет весь исходный код. Google Reader уничтожен «горой кодового дерьма» Официально выпущена Ubuntu 24.04 LTS Перед официальным выпуском Fedora Linux 40 разработчики Microsoft: производительность Windows 11 «смехотворно плоха», Ма Хуатэн и Чжоу Хунъи пожимают друг другу руки, «устраняя обиды» Известные игровые компании издали новые правила: свадебные подарки сотрудникам не должны превышать 100 000 юаней. Pinduoduo был осужден за недобросовестную конкуренцию. Компенсация в размере 5 миллионов юаней.
{{o.name}}
{{м.имя}}

рекомендация

отmy.oschina.net/u/6919515/blog/11053926