2011-11-25 16 views
5

Znalazłem to w jakimś kodzie, który chciałem zoptymalizować. Oto snipet:Czy to normalne zachowanie w regex Java?

tempString = bigBuffer.replaceAll("\\n", ""); 
tempString = tempString.replaceAll("\\t", ""); 

Potem zdecydowałem się użyć wyrażenia regularnego mądrze i zrobiłem tak:

tempString = bigBuffer.replaceAll("[\\n\\t]", ""); 

Wtedy przyjaciel powiedział mi to zrobić w zamian:

tempString = bigBuffer.replaceAll("\\n|\\t", ""); 

Ponieważ lubię znać wynik moich zmian, zrobiłem test, aby sprawdzić, czy to była dobra optymalizacja. Tak więc wynik z (java wersja "1.6.0_27") jest z pierwszym kodem będącym odniesieniem 100%.
Z rurką to 121%, więc wykonanie tego zadania zajęło więcej czasu.

Za pomocą wspornika kwadratowego jest to 52%, więc wykonanie tego zadania zajęło mniej czasu.

Dlaczego regex zachowuje się inaczej tam, gdzie powinno być to samo?

Martin

+0

Dlaczego to powinno być to samo? – BoltClock

+0

Uważam, że powinno być tak samo, ponieważ robi to samo. Być może kompilator potrzebuje optymalizacji, gdy potok jest używany z pojedynczym znakiem. – Martin

Odpowiedz

4

Pierwszy fragment kodu wygląda przez bigBuffer dwa razy, pierwszy raz Wymiana nowych linii, a po raz drugi zastępuje karty.

Drugi fragment kodu przeszukałby BigBuffer tylko raz, sprawdzając, czy każda z nich jest taka czy inna. Spowoduje to, że wykańczanie prędkości zajmie tylko połowę czasu.

Fragment kodu na trzecim miejscu jest prawdopodobnie słabo skompilowany, co skutkuje szczególnie złą wersją algorytmu pierwszego kodu, chociaż nie mogłem powiedzieć tego na pewno, bez dokładnego zbadania ścieżki przez kompilację regex.

Doskonała praca przy testowaniu. Względny czas (w oparciu o procent) jest użyteczny, absolutny czas (milisekunda lub kilka takich) nie jest.

2

Ogólnie mówiąc, klasa znaków ([abc]) wydaje się być bardziej wydajna niż odpowiednia alternacja (a|b|c), więc nie wiem, dlaczego twój przyjaciel sugerowałby to. Ale w Javie klasy znaków, które pasują tylko do znaków z repertuaru Latin1 (tj. Pierwszych 256 punktów kodowych Unicode) są dalej optymalizowane. Prawdopodobnie dlatego widzisz tak dużą różnicę między drugą a trzecią techniką.

Ponownie, to tylko w Javie. W Perlu oczekiwałbym, że różnica pomiędzy naprzemiennością a klasą znaków będzie nieznaczna, a jest to bardziej dojrzała implementacja. W grep prawdopodobnie trudno byłoby zmierzyć różnicę bez względu na to, z którego z trzech podejść skorzystałeś - jest to po prostu tak szybko.

Ale z reguły, jeśli masz wybór między używaniem klasy postaci lub alternacji, powinieneś preferować klasę postaci. Może nie być szybszy, ale zdecydowanie nie będzie wolniejszy. I niestosownie używane, alternacja może mieć katastrofalny wpływ na wydajność.

+0

Dzięki za regułę, dopilnuję, aby mój przyjaciel o tym wiedział. – Martin

Powiązane problemy