2017-01-03 19 views
18

Mam kod aplikacji, który generuje reguła dynamicznie z config dla niektórych parsowania. Podczas sprawdzania w czasie dwóch wersji zmienna regex z każdą częścią wyodrębnianego wyrażenia OR jest zauważalnie wolniejsza od zwykłego wyrażenia regularnego niż . Powód byłby narzutem pewnych operacji wewnętrznych w module regex.Dlaczego wyszukiwanie regex jest wolniejsze dzięki przechwytywaniu grup w Pythonie?

>>> import timeit 
>>> setup = ''' 
... import re 
... ''' 

#no capture group 
>>> print(timeit.timeit("re.search(r'hello|bye|ola|cheers','some say hello,some say bye, or ola or cheers!')", setup=setup)) 
0.922958850861 

#with capture group 
>>> print(timeit.timeit("re.search(r'(hello)|(bye)|(ola)|(cheers)','some say hello,some say bye, or ola or cheers!')", setup=setup)) 
1.84023 

#no capture group 
>>> print(timeit.timeit("re.search(r'hello|bye|ola|cheers','some say hello,some say bye, or ola or cheers!')", setup=setup)) 
0.913202047348 

# capture group 
>>> print(timeit.timeit("re.search(r'(hello)|(bye)|(ola)|(cheers)','some say hello,some say bye, or ola or cheers!')", setup=setup)) 
1.41544604301 

Pytanie: Co powoduje to znaczny spadek wydajności podczas korzystania z grupy przechwytywania?

+2

Już napisałem, że * powodem byłoby narzut niektórych operacji wewnętrznie w module regex. * Co to są Państwo zainteresowani? Co się stanie, jeśli we wzorcu zostaną przechwycone grupy? –

+1

Określasz * w Pythonie * - czy mówisz, że moduł Python 're' jest znacznie wolniejszy niż silnik RE w innym języku (używając tego samego RE i danych)? Jeśli tak, czy mógłbyś pokazać dokonane porównania, proszę? – cdarke

+0

@ WiktorStribiżew Tak, interesuje się tym, co powoduje to wewnętrznie. – DhruvPathak

Odpowiedz

10

Twoje wzory różnią się tylko w grupach przechwytywania. Po zdefiniowaniu grupy przechwytującej w schemacie regex i użyciu wzorca z re.search, wynikiem będzie instancja MatchObject. Każdy obiekt dopasowywania będzie zawierał tyle grup , ponieważ przechwytują grupy we wzorcu, nawet jeśli są puste. To jest obciążenie dla elementów wewnętrznych re: dodawanie grup (listy) (przydzielanie pamięci itp.). Pamiętaj, że grupy zawierają również takie szczegóły, jak the starting and ending index of the text that they match i więcej (patrz: MatchObject reference).

+0

Dlaczego to "(?: Hello | bye | ola | cheerle)" jest szybsze niż to: 'hello | bye | ola | cheers'? – MYGz

+0

Masz na myśli wzór jest samodzielny? Funkcjonalnie są one takie same, ponieważ tylko grupa 0 (cały mecz) jest tworzona po uruchomieniu obu. –

+0

Testowany na 'łańcuchu' z pytaniem 're.search'. Ten pierwszy jest nieco szybszy. – MYGz

18

Powód jest dość prosty, użycie grup przechwytywania oznacza, że ​​silnik zapisuje zawartość w pamięci, podczas gdy użycie grupy przechwytywania wskazuje, że silnik nie zapisuje niczego. Weź pod uwagę, że mówisz silnikowi, aby wykonał więcej operacji.

Na przykład, użycie tego wyrażenia (hello|bye|ola|cheers) lub (hello)|(bye)|(ola)|(cheers) wpłynie znacząco na wyniki w porównaniu z grupą atomową lub nie przechwytującą, taką jak (?:hello|bye|ola|cheers).

Podczas korzystania z wyrażenia regularnego wiesz, czy chcesz przechwytywać, czy nie, przechwytywać treści, takie jak powyższy przypadek. Jeśli chcesz uchwycić dowolne z tych słów, stracisz wydajność, ale jeśli nie potrzebujesz przechwytywać zawartości, możesz zaoszczędzić wydajność, poprawiając ją, tak jak w przypadku niezapisywania grup.

Wiem, że oznaczono pythonem, ale masz przygotowałem test porównawczy online dla javascript, aby pokazać, jak wychwytywanie i przechwytywanie grup wpływa na silnik js regex.

https://jsperf.com/capturing-groups-vs-non-capturing-groups

enter image description here

+0

Różnice te są znacznie mniejsze niż w teście OP (wprawdzie ograniczony). – usr2564301

+0

@RadLexus, tak, to też zwróciło moją uwagę. Nie wiem, jak wykonuje się silnik z python regex z przechwytywaniem grupy i zmianami. Bardzo lubię jsperf, ponieważ pomaga on w łatwym wykonywaniu testów, ale jest to js zamiast python. W każdym razie, moim pomysłem było pokazanie, że używanie grup przechwytujących jest droższe niż używanie grup niezapisujących lub żadnych grup. –

+0

O ile Python's regex nie jest bardziej nieefektywny niż JavaScript, różnice te są na tyle małe, że można je uznać za nieistotne. Jestem skłonny do wewnętrznego zarządzania obiektami wewnątrz Pythona. Fakt, że jedno wyrażenie tworzy więcej obiektów niż inny, nie jest wtedy "przyczyną" - innym rozwiązaniem bez regex, ale * z * taką samą liczbą dodatkowych obiektów również byłoby wolniejsze. – usr2564301