So beschleunigen Sie reguläre Ausdrücke unter Produktionsdruck

Wenn Sie die Regex-Methode trennen und einen Benchmark verwenden können, um den Vergleich zu überprüfen, können Sie die Regex beschleunigen, wenn Sie es wirklich brauchen.

Übersetzt aus „ How to Speed ​​up Regular Expressions under Production Pressure“ , Autor David Eastman.

Ich fühle mich ein wenig schuldig, wenn es darum geht, auf die Vorteile der Verwendung regulärer Ausdrücke hinzuweisen , da ich ihre Vorteile in mehreren Artikeln erwähnt habe , aber nie erwähnt habe, dass sie langsam sein können.

In vielen Anwendungsfällen ist die Geschwindigkeit regulärer Ausdrücke kein Problem. Es erfasst lediglich einige Fragen über ein Formular. Aber wenn es auf Geschwindigkeit ankommt, sind Sie plötzlich ein Detektiv, der nach einem Zeitkiller sucht. Dies zwingt Sie dazu, herauszufinden, welche Codeteile ineffizient sind, aber die Geschwindigkeit unter Produktionsdruck zu erhöhen, ist eine große Herausforderung.

Ich verwende ein C#-Beispiel, aber im Endeffekt müssen Sie im Allgemeinen darauf achten, wie Sie reguläre Ausdrücke in der von Ihnen verwendeten Sprache verwenden, und Optionen wie das Kompilieren regulärer Ausdrücke können hilfreich sein.

Wenn ich Ausführungsgeschwindigkeiten vergleiche, muss ich eine Art Benchmark-Tool verwenden, um einen gültigen Vergleich anzustellen. Glücklicherweise gibt es BenchmarkDotNet bereits. Es funktioniert für Konsolenanwendungen, was wir brauchen.

Ich werde weiterhin Visual Studio Code verwenden, da es sich besser zum Erstellen und Anzeigen von Projekten eignet, ohne dass Lösungen erforderlich sind. Um die Sache zu beschleunigen, werde ich Vorlagen verwenden.

Beim Öffnen von Warp habe ich zunächst die folgenden Schritte ausgeführt:

Dadurch wird lediglich ein für uns benanntes Projekt eingerichtet, wobei die verfügbare Benchmark-VorlageBenchmarkRegex verwendet wird, um das entsprechende Projekt-Framework einzurichten. Wir können die generierten Dateien sehen, die sich im Verzeichnis befinden:

Anschließend können wir code .VS Code mit dem Befehl starten.

Aber betrachten wir zunächst einige reguläre Ausdrucksaufgaben, die ich in meinem vorherigen Artikel ausgeführt habe. Wir haben ein kniffliges Muster verwendet , das Alternation und Lookaround verwendet, um zu zeigen, dass „i before e außer after c“ im Englischen oft gebrochen wird:

Das obige Muster findet destruktive Beispiele, indem es nach „cie“ oder „ei“ ohne ein „c“ sucht. Beachten Sie, dass Lookaround eine der Funktionen in regulären Ausdrücken ist, die sich in verschiedenen Implementierungen unterschiedlich verhalten können und mit Vorsicht verwendet werden sollten. In diesem Fall verwenden wir einen negativen Lookahead (?<!c), um zu bestätigen, dass „ei“ kein „c“ vorangestellt ist, aber dieses „c“ nicht verbraucht. Weitere Informationen finden Sie im Artikel.

Wir können diesen Beispieltext und dieses Muster direkt in unsere neue Vorlagendatei _Benchmark.cs_ einfügen:

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; 
      } 
   } 
}

Zuerst prüfen wir, ob die Übereinstimmung gültig ist und ob die sechs Fälle erfasst wurden.

Wir können die Konsolenanwendung nur im Release-Modus testen, was in Ordnung ist, damit wir sie über die Warp-Befehlszeile ausführen können dotnet run -C Release. Bald erhielten wir in den Protokollen die Bestätigung, dass sechs Fälle erfasst wurden:

Schließlich erhalten wir den Benchmark:

OK großartig. Jetzt müssen wir natürlich wieder auf unser Thema zurückkommen, nämlich die Beschleunigung regulärer Ausdrücke. Der erste und ziemlich naheliegende Ansatz besteht also darin, das Schema statisch zu machen . Nachdem wir nun bestätigt haben, dass das Muster funktioniert, können wir auf den Ausdruck verzichten, da er den Benchmark schließlich sehr langsam macht!

.. 
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); 
} 
..

Daher gehen wir ungefähr davon aus, dass das zweite Szenario schneller sein wird. Das ist tatsächlich der Fall:

(Ja, ohne Drucken sind wir im Nanosekundenbereich.)

Nachdem wir nun den Benchmark getestet haben, können wir die Kompilierungsoptionen testen:

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); 
} 
..

Wie schneidet dieser Benchmark ab?

Na ja, ungefähr die Hälfte. Dies ist jedoch keine eindeutige Schlussfolgerung. Es passiert eine Menge in und um es herum, worüber Sie Bescheid wissen müssen.

Als Sie zum ersten Mal C# verwendet haben, erinnern Sie sich vielleicht daran, dass es in eine Zwischensprache (IL oder MSIL) übersetzt und dann per Just-in-Time- Kompilierung (JIT) in das native Format des Betriebssystems kompiliert wurde . (Dies schien bei der Veröffentlichung von C# im Jahr 2000 einigermaßen irrelevant zu sein, da Microsoft eng an Windows gebunden war.)

Regex generiert jedoch seine eigenen Knoten, Analysebäume und Operationen und konvertiert sie dann in IL. Bedenken Sie, dass Regex eine ältere Technologie als .NET ist – etwa ein halbes Jahrhundert. Dies erklärt zum Teil, warum es im Umgang damit besondere Regeln gibt.

Ohne das Compile-Flag wird das instanziierte Regex-Objekt als der oben genannte Satz interner Operationen interpretiert. Diese Operationscodes werden in IL konvertiert, sodass der JIT-Compiler sie ausführen kann, wenn Methoden für das Objekt (z. B. _Match_) aufgerufen werden. Dies ist in Ordnung, wenn Sie nur wenige Regex-Aufrufe tätigen. Wenn die Regex-Definition statisch ist , wird der Operationscode zwischengespeichert . Standardmäßig werden die 15 zuletzt verwendeten Aktionscodes zwischengespeichert. Wenn Sie viele Schemata verwenden, können Sie diese Einstellung mit der Eigenschaft Regex.CacheSize ändern.

Wenn das Compile-Flag verwendet wird, erhöhen vorkompilierte reguläre Ausdrücke die Startzeit, aber die Ausführung einzelner Mustervergleichsmethoden ist schneller. Dies ist nützlich, wenn Sie bestimmte Muster wiederholt verwenden.

Sie können ein Regex-Objekt und -Schema erstellen, es kompilieren und in einer eigenständigen Assembly speichern . Sie können die Regex.CompileToAssembly- Methode aufrufen, um sie zu kompilieren und zu speichern. Es ist jedoch sinnvoll, dies beim Entwurf zu berücksichtigen, da Sie Ihre Anwendung in separate Baugruppen aufteilen.

Zusammenfassend lässt sich sagen, dass Regex überhaupt nicht in zeitkritischen Bereichen eingesetzt werden sollte. Wenn Sie nur wenige Ausdrücke ausführen, ist es am besten, dies auf die übliche interpretierte Weise zu tun. Wenn Sie dasselbe Muster häufig ausführen, verwenden Sie das Compile-Flag oder fügen Sie sie in separate Assemblys ein. Wenn Sie letztendlich die Regex-Methode isolieren und einen Benchmark verwenden können, um den Vergleich zu überprüfen, können Sie den Zeitkiller in Aktion erleben.

Dieser Artikel wurde zuerst auf Yunyunzhongsheng ( https://yylives.cc/ ) veröffentlicht, jeder ist herzlich willkommen.

Ich habe beschlossen, Open-Source-Hongmeng aufzugeben . Wang Chenglu, der Vater von Open-Source-Hongmeng: Open-Source-Hongmeng ist die einzige Architekturinnovations- Industriesoftwareveranstaltung im Bereich Basissoftware in China – OGG 1.0 wird veröffentlicht, Huawei steuert den gesamten Quellcode bei Google Reader wird vom „Code-Scheißberg“ getötet Ubuntu 24.04 LTS wird offiziell veröffentlicht Vor der offiziellen Veröffentlichung von Fedora Linux 40 Microsoft-Entwickler: Die Leistung von Windows 11 ist „lächerlich schlecht“, Ma Huateng und Zhou Hongyi geben sich die Hand, „beseitigen den Groll“ Namhafte Spielefirmen haben neue Vorschriften erlassen: Hochzeitsgeschenke an Mitarbeiter dürfen 100.000 Yuan nicht überschreiten. Pinduoduo wurde wegen unlauteren Wettbewerbs zu einer Entschädigung von 5 Millionen Yuan verurteilt
{{o.name}}
{{m.name}}

Ich denke du magst

Origin my.oschina.net/u/6919515/blog/11053926
Empfohlen
Rangfolge