Co dzieje się za kulisami, gdy oznaczysz wyrażenie regularne jako do kompilacji? Czym to się różni / różni od wyrażenia regularnego w pamięci podręcznej?
Korzystając z tych informacji, jak określić, kiedy koszt obliczeń jest znikomy w porównaniu ze wzrostem wydajności?
Odpowiedzi:
RegexOptions.Compiled
nakazuje aparatowi wyrażeń regularnych skompilowanie wyrażenia regularnego do IL przy użyciu lekkiego generowania kodu ( LCG ). Ta kompilacja ma miejsce podczas budowy obiektu i mocno go spowalnia. Z kolei dopasowania przy użyciu wyrażenia regularnego są szybsze.Jeśli nie określisz tej flagi, wyrażenie regularne będzie traktowane jako „zinterpretowane”.
Weź ten przykład:
Wykonuje 4 testy na 3 różnych wyrażeniach regularnych. Najpierw testuje pojedyncze dopasowanie jednorazowe (skompilowane vs nieskompilowane). Po drugie, testuje powtórzone dopasowania, które wykorzystują to samo wyrażenie regularne.
Wyniki na moim komputerze (skompilowane w wersji, bez dołączonego debugera)
1000 pojedynczych dopasowań (skonstruuj regex, dopasuj i usuń)
1,000,000 dopasowań - ponowne użycie obiektu Regex
Te wyniki pokazują, że skompilowane wyrażenia regularne mogą być nawet o 60% szybsze w przypadkach, gdy ponownie używasz
Regex
obiektu. Jednak w niektórych przypadkach może być o ponad 3 rzędy wielkości wolniejsze do skonstruowania.Pokazuje również, że wersja .NET x64 może być od 5 do 6 razy wolniejsza, jeśli chodzi o kompilację wyrażeń regularnych.
Zaleca się użycie wersji skompilowanej w przypadkach, gdy albo
Klucz w przygotowaniu, pamięć podręczna Regex
Silnik wyrażeń regularnych zawiera pamięć podręczną LRU, która przechowuje 15 ostatnich wyrażeń regularnych, które zostały przetestowane przy użyciu statycznych metod
Regex
klasy.Na przykład
Regex.Replace
,Regex.Match
etc .. wszystko użycie cache Regex.Rozmiar pamięci podręcznej można zwiększyć, ustawiając
Regex.CacheSize
. Akceptuje zmiany rozmiaru w dowolnym momencie podczas cyklu życia aplikacji.Nowe wyrażenia regularne są buforowane tylko przez pomocników statycznych w klasie Regex. Jeśli konstruujesz obiekty, pamięć podręczna jest sprawdzana (pod kątem ponownego użycia i zderzenia), jednak utworzone wyrażenie regularne nie jest dołączane do pamięci podręcznej .
Ta pamięć podręczna jest trywialną pamięcią podręczną LRU, jest zaimplementowana za pomocą prostej podwójnie połączonej listy. Jeśli zdarzy się, że zwiększysz ją do 5000 i użyjesz 5000 różnych wywołań pomocników statycznych, każda konstrukcja wyrażenia regularnego będzie przeszukiwać 5000 wpisów, aby sprawdzić, czy została wcześniej zapisana w pamięci podręcznej. Wokół czeku znajduje się blokada , więc kontrola może zmniejszyć równoległość i wprowadzić blokowanie gwintu.
Ta liczba jest ustawiona dość nisko, aby uchronić się przed takimi przypadkami, chociaż w niektórych przypadkach możesz nie mieć innego wyjścia, jak ją zwiększyć.
Moim stanowczym zaleceniem nigdy nie byłoby przekazanie
RegexOptions.Compiled
opcji statycznemu pomocnikowi.Na przykład:
Powodem jest to, że bardzo ryzykujesz przegapienie pamięci podręcznej LRU, co spowoduje bardzo kosztowną kompilację. Ponadto nie masz pojęcia, na czym polegasz biblioteki, więc masz niewielkie możliwości kontrolowania lub przewidywania najlepszego możliwego rozmiaru pamięci podręcznej.
Zobacz też: blog zespołu BCL
Uwaga : dotyczy to .NET 2.0 i .NET 4.0. Istnieją pewne oczekiwane zmiany w 4.5, które mogą spowodować, że zostanie to zmienione.
źródło
Compiled
w kodzie strony internetowej, w której faktycznie przechowuję obiekt statyczny (obejmujący całą aplikację)Regex
. Tak więcRegex
jedyny musi być zbudowany raz, gdy IIS uruchamia aplikację, a następnie jest ponownie używany tysiące razy. Działa to dobrze, o ile aplikacja nie restartuje się często.Ten wpis na blogu zespołu BCL daje ładny przegląd: „ Wydajność wyrażeń regularnych ”.
Krótko mówiąc, istnieją trzy typy wyrażeń regularnych (każdy jest wykonywany szybciej niż poprzedni):
interpretowane
szybkie tworzenie w locie, wolne wykonywanie
skompilowany (ten, o który wydajesz się pytać)
wolniejszy do tworzenia w locie, szybki do wykonania (dobry do wykonywania w pętlach)
wstępnie skompilowane
tworzenie w czasie kompilacji aplikacji (bez kary za tworzenie w czasie wykonywania), szybkie wykonanie
Tak więc, jeśli zamierzasz wykonać to wyrażenie regularne tylko raz lub w sekcji aplikacji, która nie ma krytycznego znaczenia dla wydajności (tj. Sprawdzanie poprawności danych wejściowych użytkownika), możesz wybrać opcję 1.
Jeśli zamierzasz uruchomić wyrażenie regularne w pętli (tj. Parsowanie pliku linia po linii), powinieneś skorzystać z opcji 2.
Jeśli masz wiele wyrażeń regularnych, które nigdy się nie zmienią w Twojej aplikacji i są używane intensywnie, możesz wybrać opcję 3.
źródło
CompileModule
. Cholera, muszę dokładniej przyjrzeć się nowej platformie.Należy zauważyć, że wydajność wyrażeń regularnych od .NET 2.0 została ulepszona dzięki pamięci podręcznej MRU nieskompilowanych wyrażeń regularnych. Kod biblioteki Regex nie reinterpretuje już tego samego nieskompilowanego wyrażenia regularnego za każdym razem.
Więc nie jest potencjalnie większa wydajność kara z skompilowany i na bieżąco wyrażenia regularnego. Oprócz wolniejszych czasów ładowania system wykorzystuje również więcej pamięci do kompilowania wyrażeń regularnych do instrukcji.
Zasadniczo obecna rada to albo nie kompiluj wyrażeń regularnych, albo kompiluj je wcześniej do oddzielnego zestawu.
Ref: BCL Team Blog Wydajność wyrażeń regularnych [David Gutierrez]
źródło
1) Zespół biblioteki klas bazowych na skompilowanym wyrażeniu regularnym
2) Coding Horror, odnoszący się do # 1 z kilkoma dobrymi punktami na temat kompromisów
źródło
Mam nadzieję, że poniższy kod pomoże ci zrozumieć koncepcję funkcji re.compile
źródło