/ / Uderzenie wydajności Perla między dwiema popularnymi metodami wyrażeń regularnych służącymi do przycinania stringów? - regex, perl

Uderzenie wydajności Perla między dwiema popularnymi metodami wyrażeń regularnych dla przycinania stringów? - regex, perl

Więc pracuję nad skryptem Perla, który wykonuje dużą ilość przetwarzania (nic zbyt skomplikowanego, ale dużo z tego) i postanowił zrobić mały benchmark, aby porównać dwie popularne metody przycinania strun.

Pierwsza metoda to szybka jedna linijka:

$word =~ s/^s+|s+$//g;

Druga metoda jest nieco dłuższa, ale robi to samo:

$word =~ s/^s+//;
$word =~ s/s+$//;

Dla moich testów miałem skrypt odczytany z pliku z 40 milionami linii, przycinając każdy (robi tylko to). Średnia długość linii wynosi poniżej 20 bajtów.

Pierwsza metoda trwała średnio 87 sekund.
Druga metoda trwała średnio 27 sekund.
Bez przetwarzania (tylko odczytanie linii, kontynuacja) zajmuje średnio 16 sekund.

Pierwsza metoda (pierwsze przejście) dopasuje wszystkie początkowe lub końcowe białe znaki, następnie usunie je, a następnie dopasuje i usunie początkowe / końcowe białe znaki po drugiej stronie.
Druga metoda dopasowuje i usuwa wszystkie wiodące białe znaki, a następnie dopasowuje i usuwa wszystkie końcowe spacje.

Może jestem w błędzie, ale dlaczego druga metoda byłaby ponad 3 razy szybsza od pierwszej?

Odpowiedzi:

5 dla odpowiedzi № 1

Ma to sens, że zakotwiczone wzorce niezawierające ścieżek zwrotnych można zoptymalizować WAY lepiej (skutecznie jeden sekwencyjny skan w przód / w tył, zaczynając od znanej pozycji znaku);

Jest szansa, że ​​"opcja" (|) spowoduje, że optymalizator zostanie wycofany i otrzymasz standardowy backtracking, całkiem źle, ponieważ może wystąpić wiele spacji, które nie są spóźnione


11 dla odpowiedzi nr 2

Silnik regex musi wykonać więcej pracy w pierwszym przypadku, a mianowicie cofnięcie w celu oceny alternatyw. Możesz zobaczyć różnicę w zaangażowanym kodzie:

echo " hello " |perl -Mre=debug -ple "s/^s+|s+$//g"
echo " hello " |perl -Mre=debug -ple "s/^s+//;s/s+$//"

2 dla odpowiedzi nr 3

Podejrzewam, że wyrażenie regularne Perla może być w stanie zoptymalizować drugą wersję za pomocą statycznej analizy wzoru. Na przykład może to zobaczyć /^foo/ musi pasować na początku ciągu. Jeśli mecz się nie powiedzie, nie ma sensu powtarzać pozostałych znaków w łańcuchu, sprawdzając mecze.

Domyślnie znak "^" gwarantuje zgodność tylko z początkiem łańcucha, znak "$" tylko z końcem (lub przed znakiem nowej linii na końcu), oraz Perl dokonuje pewnych optymalizacji przy założeniu, że ciąg zawiera tylko jedną linię.

Źródło (Podkreśl moje.)

Pierwsza wersja jest bardziej skomplikowanym wyrażeniem i nie jest tak łatwo zoptymalizowana.