Gdy grep
lub sed
są używane z opcją, --extended-regexp
a wzorzec {1,9999}
jest częścią używanego wyrażenia regularnego, wydajność tych poleceń staje się niska. Aby być bardziej zrozumiałym, poniżej zastosowano kilka testów. [1] [2]
- Względna wydajność
grep -E
,egrep
ised -E
jest prawie równa, więc tylko testy, które zostały wykonane zgrep -E
są świadczone.
Test 1
$ time grep -E '[0-9]{1,99}' < /dev/null
real 0m0.002s
Test 2
$ time grep -E '[0-9]{1,9999}' < /dev/null
> real 0m0.494s
Test 3
$ grep -E '[0123456789] {1,9999}' </ dev / null > prawdziwe 21m43.947s
Test 4
$ time grep -E '[0123456789]+' < /dev/null
$ time grep -E '[0123456789]*' < /dev/null
$ time grep -E '[0123456789]{1,}' < /dev/null
$ time grep -P '[0123456789]{1,9999}' < /dev/null
real 0m0.002s
Jaki jest powód tak znaczącej różnicy w wydajności?
command-line
grep
regex
pa4080
źródło
źródło
[0-9]+
)time grep -E '[0-9]{1,99}' </dev/null
kontratime grep -E '[0-9]{1,9999}' </dev/null
. Nawet bez danych wejściowych drugie polecenie jest powolne (16.04). Zgodnie z oczekiwaniami, z pominięciem-E
i ucieczki{
i}
zachowuje się tak samo i zastępując-E
z-P
nie wolno (PCRE jest inny silnik). Najciekawsze jest to, jak wiele szybciej[0-9]
jest niż.
,x
a nawet[0123456789]
. Z żadnym z tych i{1,9999}
,grep
zużywa ogromną ilość pamięci RAM; Nie odważyłem się, aby działał dłużej niż ~ 10 minut.{
}
są'
'
cytowane ; pocisk przekazuje je w niezmienionej postacigrep
. W każdym razie{1,9999}
byłoby to bardzo szybkie i proste rozszerzenie nawiasów klamrowych . Powłoka po prostu ją rozszerzy1 9999
.ps
itop
do sprawdzenia, czygrep
przekazano oczekiwane argumenty i czy niebash
zużywa dużo pamięci RAM i procesora. Oczekujęgrep
ised
używam funkcji regex POSIX zaimplementowanych w libc do dopasowywania BRE / ERE; Nie powinienem tak naprawdę mówić ogrep
projektowaniu, chyba żegrep
programiści postanowili korzystać z tej biblioteki.time grep ... < /dev/null
, aby ludzie nie połączyli rzeczywistego problemu z danymi, które zostały dostarczone,grep
i innymi istotami obcymi.Odpowiedzi:
Zauważ, że to nie dopasowanie zajmuje dużo czasu, ale budowa RE. Przekonasz się, że zużywa również sporo pamięci RAM:
Liczba przydziałów wydaje się w przybliżeniu proporcjonalna do liczby iteracji, ale przydzielona pamięć wydaje się rosnąć wykładniczo.
To zależy od sposobu implementacji wyrażeń regularnych GNU. Jeśli skompilować GNU
grep
zCPPFLAGS=-DDEBUG ./configure && make
i uruchomić te polecenia, zobaczysz gwałtowny efekt w działaniu. Głębsze niż to oznaczałoby przejrzenie wielu teorii na temat DFA i zanurzenie się w implementacji regexp gnulib.Tutaj możesz zamiast tego użyć PCRE, które nie wydają się mieć tego samego problemu:
grep -Po '[0-9]{1,65535}'
(maksimum, chociaż zawsze możesz robić rzeczy takie jak[0-9](?:[0-9]{0,10000}){100}
dla 1 do 1 000 0001 powtórzeń) nie zajmuje więcej czasu ani pamięci niżgrep -Po '[0-9]{1,2}'
.źródło
grep -Po '[0-9]{1,9999}
co nie wydaje się mieć problemu.sed -E
lubgrep -E
, ale wawk
również posiada tę niską wydajność (około ostatniego polecenia awk). możeawk
także nie możesz używać PCRE?